Merge branch 'master' into windows-clang

This commit is contained in:
qurious-pixel 2025-10-31 07:39:37 -07:00 committed by Live session user
commit 9b88fe2c44
50 changed files with 399 additions and 127 deletions

View file

@ -8,6 +8,9 @@ export HOMEBREW_NO_INSTALL_CLEANUP=1
brew install -f --overwrite --quiet ccache pipenv "llvm@$LLVM_COMPILER_VER"
brew link -f --overwrite --quiet "llvm@$LLVM_COMPILER_VER"
# shellcheck disable=SC3009
rm /usr/local/bin/{idle3.14,pip3.14,pydoc3.14,python3.14,python3.14-config} && \
rm /usr/local/bin/{idle3,pip3,pydoc3,python3,python3-config}
arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
arch -x86_64 /usr/local/bin/brew install -f --overwrite --quiet ffmpeg@5 "llvm@$LLVM_COMPILER_VER" glew sdl3 vulkan-headers
arch -x86_64 /usr/local/bin/brew link -f --overwrite --quiet "llvm@$LLVM_COMPILER_VER" ffmpeg@5
@ -54,7 +57,8 @@ export Qt6_DIR="$WORKDIR/qt-downloader/$QT_VER/clang_64/lib/cmake/Qt$QT_VER_MAIN
export SDL3_DIR="$BREW_X64_PATH/opt/sdl3/lib/cmake/SDL3"
export PATH="/opt/homebrew/opt/llvm@$LLVM_COMPILER_VER/bin:$WORKDIR/qt-downloader/$QT_VER/clang_64/bin:$BREW_BIN:$BREW_SBIN:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Library/Apple/usr/bin:$PATH"
export LDFLAGS="-L$BREW_X64_PATH/lib -Wl,-rpath,$BREW_X64_PATH/lib"
# shellcheck disable=SC2155
export LDFLAGS="-L$BREW_X64_PATH/lib -Wl,-rpath,$BREW_X64_PATH/lib,-L$(brew --prefix llvm)/lib/c++"
export CPPFLAGS="-I$BREW_X64_PATH/include -msse -msse2 -mcx16 -no-pie -D__MAC_OS_X_VERSION_MIN_REQUIRED=140000"
export CFLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=140000"
export LIBRARY_PATH="$BREW_X64_PATH/opt/llvm@$LLVM_COMPILER_VER/lib:$BREW_X64_PATH/lib"

View file

@ -14,7 +14,7 @@ if [ "$DEPLOY_APPIMAGE" = "true" ]; then
curl -fsSLo linuxdeploy-plugin-checkrt.sh https://github.com/darealshinji/linuxdeploy-plugin-checkrt/releases/download/continuous/linuxdeploy-plugin-checkrt.sh
chmod +x ./linuxdeploy-plugin-checkrt.sh
export EXTRA_PLATFORM_PLUGINS="libqwayland-egl.so;libqwayland-generic.so"
export EXTRA_PLATFORM_PLUGINS="libqwayland.so"
export EXTRA_QT_PLUGINS="svg;wayland-decoration-client;wayland-graphics-integration-client;wayland-shell-integration;waylandcompositor"
APPIMAGE_EXTRACT_AND_RUN=1 linuxdeploy --appdir AppDir --plugin qt --plugin checkrt

View file

@ -32,10 +32,8 @@ rm -rf "rpcs3.app/Contents/Frameworks/QtPdf.framework" \
../../.ci/optimize-mac.sh rpcs3.app
# Hack
install_name_tool \
-delete_rpath /opt/homebrew/lib \
-delete_rpath /opt/homebrew/opt/llvm@$LLVM_COMPILER_VER/lib RPCS3.app/Contents/MacOS/rpcs3
#-delete_rpath /opt/homebrew1/Cellar/sdl3/3.2.8/lib
install_name_tool -delete_rpath /opt/homebrew/lib RPCS3.app/Contents/MacOS/rpcs3 || echo "Hack for deleting rpath /opt/homebrew/lib not needed"
install_name_tool -delete_rpath /opt/homebrew/opt/llvm@$LLVM_COMPILER_VER/lib RPCS3.app/Contents/MacOS/rpcs3 || echo "Hack for deleting rpath /opt/homebrew/opt/llvm@$LLVM_COMPILER_VER/lib not needed"
# Need to do this rename hack due to case insensitive filesystem
mv rpcs3.app RPCS3_.app

View file

@ -16,7 +16,8 @@ echo "AVVER=$AVVER" >> ../.ci/ci-vars.env
cd bin
mkdir "rpcs3.app/Contents/lib/"
cp "/usr/local/opt/llvm@$LLVM_COMPILER_VER/lib/c++/libc++abi.1.0.dylib" "rpcs3.app/Contents/lib/libc++abi.1.dylib"
cp "/usr/local/opt/llvm@$LLVM_COMPILER_VER/lib/c++/libc++abi.1.0.dylib" "rpcs3.app/Contents/Frameworks/libc++abi.1.dylib"
cp "/usr/local/opt/llvm@$LLVM_COMPILER_VER/lib/unwind/libunwind.1.dylib" "rpcs3.app/Contents/Frameworks/libunwind.1.dylib"
cp "$(realpath /usr/local/lib/libsharpyuv.0.dylib)" "rpcs3.app/Contents/lib/libsharpyuv.0.dylib"
cp "$(realpath /usr/local/lib/libintl.8.dylib)" "rpcs3.app/Contents/lib/libintl.8.dylib"

View file

@ -30,23 +30,23 @@ jobs:
matrix:
include:
- os: ubuntu-24.04
docker_img: "rpcs3/rpcs3-ci-jammy:1.6"
docker_img: "rpcs3/rpcs3-ci-jammy:1.7"
build_sh: "/rpcs3/.ci/build-linux.sh"
compiler: clang
UPLOAD_COMMIT_HASH: d812f1254a1157c80fd402f94446310560f54e5f
UPLOAD_REPO_FULL_NAME: "rpcs3/rpcs3-binaries-linux"
- os: ubuntu-24.04
docker_img: "rpcs3/rpcs3-ci-jammy:1.6"
docker_img: "rpcs3/rpcs3-ci-jammy:1.7"
build_sh: "/rpcs3/.ci/build-linux.sh"
compiler: gcc
- os: ubuntu-24.04-arm
docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:1.6"
docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:1.7"
build_sh: "/rpcs3/.ci/build-linux-aarch64.sh"
compiler: clang
UPLOAD_COMMIT_HASH: a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1
UPLOAD_REPO_FULL_NAME: "rpcs3/rpcs3-binaries-linux-arm64"
- os: ubuntu-24.04-arm
docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:1.6"
docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:1.7"
build_sh: "/rpcs3/.ci/build-linux-aarch64.sh"
compiler: gcc
name: RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }}
@ -136,7 +136,7 @@ jobs:
CCACHE_DIR: /tmp/ccache_dir
QT_VER: '6.7.3'
QT_VER_MAIN: '6'
LLVM_COMPILER_VER: '19'
LLVM_COMPILER_VER: '21'
RELEASE_MESSAGE: ../GitHubReleaseMessage.txt
UPLOAD_COMMIT_HASH: ${{ matrix.UPLOAD_COMMIT_HASH }}
UPLOAD_REPO_FULL_NAME: ${{ matrix.UPLOAD_REPO_FULL_NAME }}

View file

@ -16,4 +16,5 @@ else()
add_subdirectory(openal-soft EXCLUDE_FROM_ALL)
add_library(3rdparty_openal INTERFACE)
target_link_libraries(3rdparty_openal INTERFACE OpenAL::OpenAL)
target_compile_options(3rdparty_openal INTERFACE -Wno-deprecated-literal-operator)
endif()

@ -1 +1 @@
Subproject commit 066d4a63b2c714b20b0a8073a01fda7c5c6763f6
Subproject commit 759ac5d698baefca53f1975a0bb1d2dcbdb9f836

View file

@ -464,6 +464,8 @@ error_code cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr<char> dirName
{
get->isNewData = CELL_HDDGAME_ISNEWDATA_NODIR;
get->getParam = {};
cellGame.warning("cellHddGameCheck(): New data.");
}
else
{
@ -476,13 +478,22 @@ error_code cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr<char> dirName
if (psf.contains("RESOLUTION")) get->getParam.resolution = ::at32(psf, "RESOLUTION").as_integer();
if (psf.contains("SOUND_FORMAT")) get->getParam.soundFormat = ::at32(psf, "SOUND_FORMAT").as_integer();
if (psf.contains("TITLE")) strcpy_trunc(get->getParam.title, ::at32(psf, "TITLE").as_string());
if (psf.contains("APP_VER")) strcpy_trunc(get->getParam.dataVersion, ::at32(psf, "APP_VER").as_string());
if (psf.contains("TITLE_ID")) strcpy_trunc(get->getParam.titleId, ::at32(psf, "TITLE_ID").as_string());
// Old games do not have APP_VER key
strcpy_trunc(get->getParam.dataVersion, psf::get_string(psf, "APP_VER", psf::get_string(sfo, "VERSION", "")));
if (psf.contains("TITLE_ID"))
{
strcpy_trunc(get->getParam.titleId, ::at32(psf, "TITLE_ID").as_string());
}
for (u32 i = 0; i < CELL_HDDGAME_SYSP_LANGUAGE_NUM; i++)
{
strcpy_trunc(get->getParam.titleLang[i], psf::get_string(psf, fmt::format("TITLE_%02d", i)));
}
cellGame.warning("cellHddGameCheck(): Data exists:\nATTRIBUTE: 0x%x, RESOLUTION: 0x%x, RESOLUTION: 0x%x, SOUND_FORMAT: 0x%x, dataVersion: %s"
, get->getParam.attribute, get->getParam.resolution, get->getParam.soundFormat, get->getParam.soundFormat, std::span<const u8>(reinterpret_cast<const u8*>(get->getParam.dataVersion), 6));
}
// TODO ?

View file

@ -224,8 +224,8 @@ enum
struct CellGameDataSystemFileParam
{
char title[CELL_GAMEDATA_SYSP_TITLE_SIZE];
char titleLang[CELL_GAMEDATA_SYSP_LANGUAGE_NUM][CELL_GAMEDATA_SYSP_TITLE_SIZE];
char titleId[CELL_GAMEDATA_SYSP_TITLEID_SIZE];
char titleLang[CELL_GAMEDATA_SYSP_LANGUAGE_NUM][CELL_GAMEDATA_SYSP_TITLE_SIZE]; // 0x80
char titleId[CELL_GAMEDATA_SYSP_TITLEID_SIZE]; // 0xA80
char reserved0[2];
char dataVersion[CELL_GAMEDATA_SYSP_VERSION_SIZE];
char reserved1[2];
@ -248,13 +248,13 @@ struct CellGameDataStatGet
{
be_t<s32> hddFreeSizeKB;
be_t<u32> isNewData;
char contentInfoPath[CELL_GAMEDATA_PATH_MAX];
char gameDataPath[CELL_GAMEDATA_PATH_MAX];
char reserved0[2];
be_t<s64> st_atime_;
be_t<s64> st_mtime_;
be_t<s64> st_ctime_;
CellGameDataSystemFileParam getParam;
char contentInfoPath[CELL_GAMEDATA_PATH_MAX]; // 0x8
char gameDataPath[CELL_GAMEDATA_PATH_MAX]; // 0x427
char reserved0[2]; // 0x846
be_t<s64> st_atime_; // 0x848
be_t<s64> st_mtime_; // 0x850
be_t<s64> st_ctime_; // 0x858
CellGameDataSystemFileParam getParam; // 0x860
be_t<s32> sizeKB;
be_t<s32> sysSizeKB;
char reserved1[68];

View file

@ -2231,6 +2231,12 @@ public:
{
for (auto& [a, b] : m_blocks)
{
if (has_gpr_memory_barriers)
{
// Dive deeper and inspect GPR store barriers
break;
}
// Check if the store occurs before any barrier in the block
if (b.store[i] && b.store[i] != bs && b.store_context_first_id[i] == 1)
{

View file

@ -425,7 +425,7 @@ extern void mov_rdata_nt(spu_rdata_t& _dst, const spu_rdata_t& _src)
#endif
}
#if defined(_MSC_VER)
#if defined(_MSC_VER) && !defined(__clang__)
#define mwaitx_func
#define waitpkg_func
#else

View file

@ -2063,7 +2063,7 @@ void lv2_obj::set_yield_frequency(u64 freq, u64 max_allowed_tsc)
g_lv2_preempts_taken.release(0);
}
#if defined(_MSC_VER)
#if defined(_MSC_VER) && !defined(__clang__)
#define mwaitx_func
#define waitpkg_func
#else

View file

@ -1329,6 +1329,16 @@ namespace vm
std::vector<std::pair<u64, u64>> event_data;
ensure(size == _page_unmap(it->first, size, this->flags, it->second.second.get(), unmapped ? *unmapped : event_data));
if (it->second.second && addr < 0xE0000000)
{
if (it->second.second.use_count() != 1)
{
fmt::throw_exception("External memory usage at block 0x%x (addr=0x%x, size=0x%x)", this->addr, it->first, size);
}
it->second.second.reset();
}
it = next;
}
@ -1338,6 +1348,8 @@ namespace vm
#ifdef _WIN32
m_common->unmap_critical(vm::get_super_ptr(addr));
#endif
ensure(m_common.use_count() == 1);
m_common.reset();
}
return true;
@ -1349,6 +1361,7 @@ namespace vm
block_t::~block_t()
{
ensure(!is_valid());
ensure(!m_common || m_common.use_count() == 1);
}
u32 block_t::alloc(const u32 orig_size, const std::shared_ptr<utils::shm>* src, u32 align, u64 flags)
@ -2244,7 +2257,11 @@ namespace vm
for (auto& block : g_locations)
{
if (block) _unmap_block(block);
if (block)
{
_unmap_block(block);
ensure(block.use_count() == 1);
}
}
g_locations.clear();

View file

@ -217,7 +217,7 @@ namespace vm
}
else
{
#ifndef _MSC_VER
#if !defined(_MSC_VER) || (defined(__clang__) && defined(_MSC_VER))
__asm__ volatile ("xend;" ::: "memory");
#else
_xend();

View file

@ -76,9 +76,9 @@ public:
data_heap(const data_heap&) = delete;
data_heap(data_heap&&) = delete;
void init(usz heap_size, const char* buffer_name = "unnamed", usz min_guard_size=0x10000)
void init(usz heap_size, const char* buffer_name = nullptr, usz min_guard_size=0x10000)
{
m_name = const_cast<char*>(buffer_name);
m_name = const_cast<char*>(buffer_name ? buffer_name : "<unnamed>");
m_size = heap_size;
m_put_pos = 0;

View file

@ -485,7 +485,7 @@ void GLGSRender::bind_texture_env()
}
else
{
auto target = gl::get_target(current_fragment_program.get_texture_dimension(i));
const auto target = gl::get_target(current_fragment_program.get_texture_dimension(i));
cmd->bind_texture(GL_FRAGMENT_TEXTURES_START + i, target, m_null_textures[target]->id());
if (current_fragment_program.texture_state.redirected_textures & (1 << i))

View file

@ -137,6 +137,8 @@ class GLGSRender : public GSRender, public ::rsx::reports::ZCULL_control
std::unique_ptr<gl::texture> m_flip_tex_color[2];
// Present
gl::fbo m_sshot_fbo;
std::unique_ptr<gl::texture> m_sshot_tex;
std::unique_ptr<gl::upscaler> m_upscaler;
output_scaling_mode m_output_scaling = output_scaling_mode::bilinear;

View file

@ -395,7 +395,7 @@ namespace gl
}
}
void ui_overlay_renderer::run(gl::command_context& cmd_, const areau& viewport, GLuint target, rsx::overlays::overlay& ui)
void ui_overlay_renderer::run(gl::command_context& cmd_, const areau& viewport, GLuint target, rsx::overlays::overlay& ui, bool flip_vertically)
{
program_handle.uniforms["viewport"] = color4f(static_cast<f32>(viewport.width()), static_cast<f32>(viewport.height()), static_cast<f32>(viewport.x1), static_cast<f32>(viewport.y1));
program_handle.uniforms["ui_scale"] = color4f(static_cast<f32>(ui.virtual_width), static_cast<f32>(ui.virtual_height), 1.f, 1.f);
@ -445,12 +445,13 @@ namespace gl
}
}
rsx::overlays::vertex_options vert_opts;
rsx::overlays::vertex_options vert_opts {};
program_handle.uniforms["vertex_config"] = vert_opts
.disable_vertex_snap(cmd.config.disable_vertex_snap)
.enable_vertical_flip(flip_vertically)
.get();
rsx::overlays::fragment_options draw_opts;
rsx::overlays::fragment_options draw_opts {};
program_handle.uniforms["fragment_config"] = draw_opts
.texture_mode(texture_mode)
.clip_fragments(cmd.config.clip_region)

View file

@ -90,7 +90,7 @@ namespace gl
void emit_geometry(gl::command_context& cmd) override;
void run(gl::command_context& cmd, const areau& viewport, GLuint target, rsx::overlays::overlay& ui);
void run(gl::command_context& cmd, const areau& viewport, GLuint target, rsx::overlays::overlay& ui, bool flip_vertically);
};
struct video_out_calibration_pass final : public overlay_pass

View file

@ -204,7 +204,8 @@ void GLGSRender::flip(const rsx::display_flip_info_t& info)
// Enable drawing to window backbuffer
gl::screen.bind();
gl::texture *image_to_flip = nullptr, *image_to_flip2 = nullptr;
gl::texture* image_to_flip = nullptr;
gl::texture* image_to_flip2 = nullptr;
if (info.buffer < display_buffers_count && buffer_width && buffer_height)
{
@ -276,15 +277,98 @@ void GLGSRender::flip(const rsx::display_flip_info_t& info)
gl::screen.clear(gl::buffers::color);
}
if (m_overlay_manager && m_overlay_manager->has_dirty())
{
m_overlay_manager->lock_shared();
std::vector<u32> uids_to_dispose;
uids_to_dispose.reserve(m_overlay_manager->get_dirty().size());
for (const auto& view : m_overlay_manager->get_dirty())
{
m_ui_renderer.remove_temp_resources(view->uid);
uids_to_dispose.push_back(view->uid);
}
m_overlay_manager->unlock_shared();
m_overlay_manager->dispose(uids_to_dispose);
}
const auto render_overlays = [this, &cmd](gl::texture* dst, const areau& aspect_ratio, bool flip_vertically = false)
{
if (m_overlay_manager && m_overlay_manager->has_visible())
{
GLuint target = 0;
if (dst)
{
m_sshot_fbo.bind();
m_sshot_fbo.color = dst->id();
target = dst->id();
}
else
{
gl::screen.bind();
}
// Lock to avoid modification during run-update chain
std::lock_guard lock(*m_overlay_manager);
for (const auto& view : m_overlay_manager->get_views())
{
m_ui_renderer.run(cmd, aspect_ratio, target, *view.get(), flip_vertically);
}
}
};
if (image_to_flip)
{
if (g_user_asked_for_screenshot || (g_recording_mode != recording_mode::stopped && m_frame->can_consume_frame()))
{
static const gl::pixel_pack_settings pack_settings{};
gl::texture* tex = image_to_flip;
if (g_cfg.video.record_with_overlays)
{
m_sshot_fbo.create();
if (!m_sshot_tex ||
m_sshot_tex->get_target() != image_to_flip->get_target() ||
m_sshot_tex->width() != image_to_flip->width() ||
m_sshot_tex->height() != image_to_flip->height() ||
m_sshot_tex->depth() != image_to_flip->depth() ||
m_sshot_tex->levels() != image_to_flip->levels() ||
m_sshot_tex->samples() != image_to_flip->samples() ||
m_sshot_tex->get_internal_format() != image_to_flip->get_internal_format() ||
m_sshot_tex->format_class() != image_to_flip->format_class())
{
m_sshot_tex = std::make_unique<gl::texture>(
GLenum(image_to_flip->get_target()),
image_to_flip->width(),
image_to_flip->height(),
image_to_flip->depth(),
image_to_flip->levels(),
image_to_flip->samples(),
GLenum(image_to_flip->get_internal_format()),
image_to_flip->format_class());
}
tex = m_sshot_tex.get();
static const position3u offset{};
gl::g_hw_blitter->copy_image(cmd, image_to_flip, tex, 0, 0, offset, offset, { tex->width(), tex->height(), 1 });
render_overlays(tex, areau(0, 0, image_to_flip->width(), image_to_flip->height()), true);
m_sshot_fbo.remove();
}
std::vector<u8> sshot_frame(buffer_height * buffer_width * 4);
glGetError();
gl::pixel_pack_settings pack_settings{};
image_to_flip->copy_to(sshot_frame.data(), gl::texture::format::rgba, gl::texture::type::ubyte, pack_settings);
tex->copy_to(sshot_frame.data(), gl::texture::format::rgba, gl::texture::type::ubyte, pack_settings);
m_sshot_tex.reset();
if (GLenum err = glGetError(); err != GL_NO_ERROR)
{
@ -296,7 +380,7 @@ void GLGSRender::flip(const rsx::display_flip_info_t& info)
}
else
{
m_frame->present_frame(sshot_frame, buffer_width * 4, buffer_width, buffer_height, false);
m_frame->present_frame(std::move(sshot_frame), buffer_width * 4, buffer_width, buffer_height, false);
}
}
@ -349,38 +433,7 @@ void GLGSRender::flip(const rsx::display_flip_info_t& info)
}
}
if (m_overlay_manager)
{
if (m_overlay_manager->has_dirty())
{
m_overlay_manager->lock_shared();
std::vector<u32> uids_to_dispose;
uids_to_dispose.reserve(m_overlay_manager->get_dirty().size());
for (const auto& view : m_overlay_manager->get_dirty())
{
m_ui_renderer.remove_temp_resources(view->uid);
uids_to_dispose.push_back(view->uid);
}
m_overlay_manager->unlock_shared();
m_overlay_manager->dispose(uids_to_dispose);
}
if (m_overlay_manager->has_visible())
{
gl::screen.bind();
// Lock to avoid modification during run-update chain
std::lock_guard lock(*m_overlay_manager);
for (const auto& view : m_overlay_manager->get_views())
{
m_ui_renderer.run(cmd, areau(aspect_ratio), 0, *view.get());
}
}
}
render_overlays(nullptr, areau(aspect_ratio));
if (g_cfg.video.debug_overlay)
{

View file

@ -353,7 +353,7 @@ namespace gl
GLenum m_aspect_flags = 0;
texture* m_image_data = nullptr;
GLenum component_swizzle[4];
GLenum component_swizzle[4] {};
texture_view() = default;

View file

@ -31,6 +31,6 @@ public:
virtual display_handle_t handle() const = 0;
virtual bool can_consume_frame() const = 0;
virtual void present_frame(std::vector<u8>& data, u32 pitch, u32 width, u32 height, bool is_bgra) const = 0;
virtual void present_frame(std::vector<u8>&& data, u32 pitch, u32 width, u32 height, bool is_bgra) const = 0;
virtual void take_screenshot(std::vector<u8>&& sshot_data, u32 sshot_width, u32 sshot_height, bool is_bgra) = 0;
};

View file

@ -104,6 +104,7 @@ namespace rsx
add_checkbox(&g_cfg.misc.show_pressure_intensity_toggle_hint, localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_SHOW_PRESSURE_INTENSITY_TOGGLE_HINT);
add_checkbox(&g_cfg.misc.show_analog_limiter_toggle_hint, localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_SHOW_ANALOG_LIMITER_TOGGLE_HINT);
add_checkbox(&g_cfg.misc.show_mouse_and_keyboard_toggle_hint, localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_SHOW_MOUSE_AND_KB_TOGGLE_HINT);
add_checkbox(&g_cfg.video.record_with_overlays, localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_RECORD_WITH_OVERLAYS);
apply_layout();
}

View file

@ -33,12 +33,14 @@ layout(%push_block) uniform Configuration
struct config_t
{
bool no_vertex_snap;
bool flip_vertically;
};
config_t unpack_vertex_options()
{
config_t result;
result.no_vertex_snap = bitfieldExtract(vertex_config, 0, 1) != 0;
result.flip_vertically = bitfieldExtract(vertex_config, 1, 1) != 0;
return result;
}
@ -47,12 +49,14 @@ vec2 snap_to_grid(const in vec2 normalized)
return floor(fma(normalized, viewport.xy, vec2(0.5))) / viewport.xy;
}
vec4 clip_to_ndc(const in vec4 coord)
vec4 clip_to_ndc(const in vec4 coord, const in bool flip_vertically)
{
vec4 ret = (coord * ui_scale.zwzw) / ui_scale.xyxy;
#ifndef VULKAN
// Flip Y for OpenGL
ret.yw = 1. - ret.yw;
if (!flip_vertically) ret.yw = 1. - ret.yw;
#else
if (flip_vertically) ret.yw = 1. - ret.yw;
#endif
return ret;
}
@ -64,12 +68,13 @@ vec4 ndc_to_window(const in vec4 coord)
void main()
{
config_t config = unpack_vertex_options();
tc0.xy = in_pos.zw;
color = albedo;
clip_rect = ndc_to_window(clip_to_ndc(clip_bounds));
clip_rect = ndc_to_window(clip_to_ndc(clip_bounds, config.flip_vertically));
vec4 pos = vec4(clip_to_ndc(in_pos).xy, 0.5, 1.);
config_t config = unpack_vertex_options();
vec4 pos = vec4(clip_to_ndc(in_pos, config.flip_vertically).xy, 0.5, 1.);
if (!config.no_vertex_snap)
{

View file

@ -59,12 +59,31 @@ namespace rsx
class vertex_options
{
private:
u32 value = 0;
void set_bit(u32 bit, bool enable)
{
if (enable)
{
value |= (1u << bit);
}
else
{
value &= ~(1u << bit);
}
}
public:
vertex_options& disable_vertex_snap(bool enable)
{
value = enable ? 1 : 0;
set_bit(0, enable);
return *this;
}
vertex_options& enable_vertical_flip(bool enable)
{
set_bit(1, enable);
return *this;
}

View file

@ -29,9 +29,9 @@ namespace vk
vk::framebuffer_holder* get_framebuffer(VkDevice dev, u16 width, u16 height, VkBool32 has_input_attachments, VkRenderPass renderpass, const std::vector<vk::image*>& image_list)
{
framebuffer_storage_key key(width, height, has_input_attachments);
auto &queue = g_framebuffers_cache[key.encoded];
auto& queue = g_framebuffers_cache[key.encoded];
for (auto &fbo : queue)
for (const auto& fbo : queue)
{
if (fbo->matches(image_list, width, height))
{
@ -42,7 +42,7 @@ namespace vk
std::vector<std::unique_ptr<vk::image_view>> image_views;
image_views.reserve(image_list.size());
for (auto &e : image_list)
for (const auto& e : image_list)
{
const VkImageSubresourceRange subres = { e->aspect(), 0, 1, 0, 1 };
image_views.push_back(std::make_unique<vk::image_view>(dev, e, VK_IMAGE_VIEW_TYPE_2D, vk::default_component_map, subres));
@ -58,9 +58,9 @@ namespace vk
vk::framebuffer_holder* get_framebuffer(VkDevice dev, u16 width, u16 height, VkBool32 has_input_attachments, VkRenderPass renderpass, VkFormat format, VkImage attachment)
{
framebuffer_storage_key key(width, height, has_input_attachments);
auto &queue = g_framebuffers_cache[key.encoded];
auto& queue = g_framebuffers_cache[key.encoded];
for (const auto &e : queue)
for (const auto& e : queue)
{
if (e->attachments[0]->info.image == attachment)
{

View file

@ -845,6 +845,7 @@ VKGSRender::~VKGSRender()
m_rtts.destroy();
m_texture_cache.destroy();
m_overlay_recording_img.reset();
m_stencil_mirror_sampler.reset();
// Queries

View file

@ -187,6 +187,8 @@ private:
VkRenderPass m_cached_renderpass = VK_NULL_HANDLE;
std::vector<vk::image*> m_fbo_images;
std::unique_ptr<vk::image> m_overlay_recording_img;
//Vertex layout
rsx::vertex_input_layout m_vertex_layout;

View file

@ -543,7 +543,7 @@ namespace vk
push_buf[14] = m_clip_region.x2;
push_buf[15] = m_clip_region.y2;
rsx::overlays::vertex_options vert_opts;
rsx::overlays::vertex_options vert_opts {};
const auto vert_config = vert_opts
.disable_vertex_snap(m_disable_vertex_snap)
.get();
@ -552,7 +552,7 @@ namespace vk
vkCmdPushConstants(cmd, program->layout(), VK_SHADER_STAGE_VERTEX_BIT, 0, 68, push_buf);
// 2. Fragment stuff
rsx::overlays::fragment_options frag_opts;
rsx::overlays::fragment_options frag_opts {};
const auto frag_config = frag_opts
.texture_mode(m_texture_type)
.clip_fragments(m_clip_enabled)

View file

@ -469,7 +469,9 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info)
}
// Scan memory for required data. This is done early to optimize waiting for the driver image acquire below.
vk::viewable_image *image_to_flip = nullptr, *image_to_flip2 = nullptr;
vk::viewable_image* image_to_flip = nullptr;
vk::viewable_image* image_to_flip2 = nullptr;
if (info.buffer < display_buffers_count && buffer_width && buffer_height)
{
vk::present_surface_info present_info
@ -613,6 +615,21 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info)
}
}
const bool has_overlay = (m_overlay_manager && m_overlay_manager->has_visible());
const auto render_overlays = [&](vk::framebuffer_holder* fbo, const areau& area)
{
if (!has_overlay) return;
// Lock to avoid modification during run-update chain
auto ui_renderer = vk::get_overlay_pass<vk::ui_overlay_renderer>();
std::lock_guard lock(*m_overlay_manager);
for (const auto& view : m_overlay_manager->get_views())
{
ui_renderer->run(*m_current_command_buffer, area, fbo, single_target_pass, m_texture_upload_buffer_ring_info, *view.get());
}
};
if (image_to_flip)
{
const bool use_full_rgb_range_output = g_cfg.video.full_rgb_range_output.get();
@ -684,7 +701,7 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info)
vk::buffer sshot_vkbuf(*m_device, utils::align(sshot_size, 0x100000), m_device->get_memory_mapping().host_visible_coherent,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT, 0, VMM_ALLOCATION_POOL_UNDEFINED);
VkBufferImageCopy copy_info;
VkBufferImageCopy copy_info {};
copy_info.bufferOffset = 0;
copy_info.bufferRowLength = 0;
copy_info.bufferImageHeight = 0;
@ -699,17 +716,55 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info)
copy_info.imageExtent.height = buffer_height;
copy_info.imageExtent.depth = 1;
vk::image* image_to_copy = image_to_flip;
if (g_cfg.video.record_with_overlays && has_overlay)
{
const auto key = vk::get_renderpass_key(m_swapchain->get_surface_format());
single_target_pass = vk::get_renderpass(*m_device, key);
ensure(single_target_pass != VK_NULL_HANDLE);
if (!m_overlay_recording_img ||
m_overlay_recording_img->type() != image_to_flip->type() ||
m_overlay_recording_img->format() != image_to_flip->format() ||
m_overlay_recording_img->width() != image_to_flip->width() ||
m_overlay_recording_img->height() != image_to_flip->height() ||
m_overlay_recording_img->layers() != image_to_flip->layers())
{
m_overlay_recording_img = std::make_unique<vk::image>(*m_device, m_device->get_memory_mapping().device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
image_to_flip->type(), image_to_flip->format(), image_to_flip->width(), image_to_flip->height(), 1, 1, image_to_flip->layers(), VK_SAMPLE_COUNT_1_BIT,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 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);
}
m_overlay_recording_img->change_layout(*m_current_command_buffer, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
image_to_flip->push_layout(*m_current_command_buffer, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
vk::copy_image_to_buffer(*m_current_command_buffer, image_to_flip, &sshot_vkbuf, copy_info);
const areai rect = areai(0, 0, buffer_width, buffer_height);
vk::copy_image(*m_current_command_buffer, image_to_flip, m_overlay_recording_img.get(), rect, rect, 1);
image_to_flip->pop_layout(*m_current_command_buffer);
m_overlay_recording_img->change_layout(*m_current_command_buffer, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
vk::framebuffer_holder* sshot_fbo = vk::get_framebuffer(*m_device, buffer_width, buffer_height, VK_FALSE, single_target_pass, { m_overlay_recording_img.get() });
sshot_fbo->add_ref();
render_overlays(sshot_fbo, areau(rect));
sshot_fbo->release();
image_to_copy = m_overlay_recording_img.get();
}
image_to_copy->push_layout(*m_current_command_buffer, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
vk::copy_image_to_buffer(*m_current_command_buffer, image_to_copy, &sshot_vkbuf, copy_info);
image_to_copy->pop_layout(*m_current_command_buffer);
flush_command_queue(true);
auto src = sshot_vkbuf.map(0, sshot_size);
const auto src = sshot_vkbuf.map(0, sshot_size);
std::vector<u8> sshot_frame(sshot_size);
memcpy(sshot_frame.data(), src, sshot_size);
sshot_vkbuf.unmap();
const bool is_bgra = image_to_flip->format() == VK_FORMAT_B8G8R8A8_UNORM;
const bool is_bgra = image_to_copy->format() == VK_FORMAT_B8G8R8A8_UNORM;
if (g_user_asked_for_screenshot.exchange(false))
{
@ -717,12 +772,11 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info)
}
else
{
m_frame->present_frame(sshot_frame, buffer_width * 4, buffer_width, buffer_height, is_bgra);
m_frame->present_frame(std::move(sshot_frame), buffer_width * 4, buffer_width, buffer_height, is_bgra);
}
}
}
const bool has_overlay = (m_overlay_manager && m_overlay_manager->has_visible());
if (g_cfg.video.debug_overlay || has_overlay)
{
if (target_layout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
@ -754,17 +808,7 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info)
direct_fbo->add_ref();
if (has_overlay)
{
// Lock to avoid modification during run-update chain
auto ui_renderer = vk::get_overlay_pass<vk::ui_overlay_renderer>();
std::lock_guard lock(*m_overlay_manager);
for (const auto& view : m_overlay_manager->get_views())
{
ui_renderer->run(*m_current_command_buffer, areau(aspect_ratio), direct_fbo, single_target_pass, m_texture_upload_buffer_ring_info, *view.get());
}
}
render_overlays(direct_fbo, areau(aspect_ratio));
if (g_cfg.video.debug_overlay)
{

View file

@ -22,12 +22,17 @@ namespace vk
if ((flags & heap_pool_low_latency) && g_cfg.video.vk.use_rebar_upload_heap)
{
// Prefer uploading to BAR if low latency is desired.
m_prefer_writethrough = memory_map.device_bar_total_bytes > (2048ull * 0x100000);
const int max_usage = memory_map.device_bar_total_bytes <= (256 * 0x100000) ? 75 : 90;
m_prefer_writethrough = can_allocate_heap(memory_map.device_bar, size, max_usage);
// Log it
if (m_prefer_writethrough && name)
if (m_prefer_writethrough)
{
rsx_log.notice("Data heap %s will attempt to use Re-BAR memory", name);
rsx_log.notice("Data heap %s will attempt to use Re-BAR memory", m_name);
}
else
{
rsx_log.warning("Could not fit heap '%s' into Re-BAR memory", m_name);
}
}
@ -86,6 +91,17 @@ namespace vk
VkBufferUsageFlags usage = heap->info.usage;
const auto& memory_map = g_render_device->get_memory_mapping();
if (m_prefer_writethrough)
{
const int max_usage = memory_map.device_bar_total_bytes <= (256 * 0x100000) ? 75 : 90;
m_prefer_writethrough = can_allocate_heap(memory_map.device_bar, aligned_new_size, max_usage);
if (!m_prefer_writethrough)
{
rsx_log.warning("Could not fit heap '%s' into Re-BAR memory during reallocation", m_name);
}
}
VkFlags memory_flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
auto memory_index = m_prefer_writethrough ? memory_map.device_bar : memory_map.host_visible_coherent;
@ -116,6 +132,14 @@ namespace vk
return true;
}
bool data_heap::can_allocate_heap(const vk::memory_type_info& target_heap, usz size, int max_usage_percent)
{
const auto current_usage = vmm_get_application_memory_usage(target_heap);
const auto after_usage = current_usage + size;
const auto limit = (target_heap.total_bytes() * max_usage_percent) / 100;
return after_usage < limit;
}
void* data_heap::map(usz offset, usz size)
{
if (!_ptr)

View file

@ -32,6 +32,7 @@ namespace vk
protected:
bool grow(usz size) override;
bool can_allocate_heap(const vk::memory_type_info& target_heap, usz size, int max_usage_percent);
public:
std::unique_ptr<buffer> heap;

View file

@ -1010,6 +1010,8 @@ namespace vk
.heap = memory_properties.memoryHeaps[i],
.types = {}
});
result.heaps.push_back({ i, memory_properties.memoryHeaps[i].flags, memory_properties.memoryHeaps[i].size });
}
for (u32 i = 0; i < memory_properties.memoryTypeCount; i++)

View file

@ -30,6 +30,8 @@ namespace vk
struct memory_type_mapping
{
std::vector<memory_heap_info> heaps;
memory_type_info host_visible_coherent;
memory_type_info device_local;
memory_type_info device_bar;

View file

@ -44,6 +44,16 @@ namespace vk
return type_ids.size();
}
u64 memory_type_info::total_bytes() const
{
u64 result = 0;
for (const auto& size : type_sizes)
{
result += size;
}
return result;
}
memory_type_info::operator bool() const
{
return !type_ids.empty();
@ -190,6 +200,23 @@ namespace vk
// Allow fastest possible allocation on start
set_fastest_allocation_flags();
// Determine the rebar heap. We will exclude it from stats
const auto& memory_map = dev.get_memory_mapping();
if (memory_map.device_bar_total_bytes !=
memory_map.device_local_total_bytes)
{
for (u32 i = 0; i < ::size32(memory_map.heaps); ++i)
{
const auto& heap = memory_map.heaps[i];
if ((heap.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) &&
heap.size == memory_map.device_bar_total_bytes)
{
m_rebar_heap_idx = i;
break;
}
}
}
}
void mem_allocator_vma::destroy()
@ -303,6 +330,12 @@ namespace vk
{
vmaGetHeapBudgets(m_allocator, stats.data());
// Filter out the Re-BAR heap
if (::size32(stats) > m_rebar_heap_idx)
{
stats[m_rebar_heap_idx].budget = 0;
}
float max_usage = 0.f;
for (const auto& info : stats)
{

View file

@ -49,6 +49,7 @@ namespace vk
const_iterator end() const;
u32 first() const;
size_t count() const;
u64 total_bytes() const;
operator bool() const;
bool operator == (const memory_type_info& other) const;
@ -58,6 +59,13 @@ namespace vk
void rebalance();
};
struct memory_heap_info
{
u32 index;
u32 flags;
u64 size;
};
class mem_allocator_base
{
public:
@ -112,6 +120,7 @@ namespace vk
private:
VmaAllocator m_allocator;
std::array<VmaBudget, VK_MAX_MEMORY_HEAPS> stats;
u32 m_rebar_heap_idx = UINT32_MAX;
};

View file

@ -245,6 +245,7 @@ enum class localized_string_id
HOME_MENU_SETTINGS_OVERLAYS_SHOW_PRESSURE_INTENSITY_TOGGLE_HINT,
HOME_MENU_SETTINGS_OVERLAYS_SHOW_ANALOG_LIMITER_TOGGLE_HINT,
HOME_MENU_SETTINGS_OVERLAYS_SHOW_MOUSE_AND_KB_TOGGLE_HINT,
HOME_MENU_SETTINGS_OVERLAYS_RECORD_WITH_OVERLAYS,
HOME_MENU_SETTINGS_PERFORMANCE_OVERLAY,
HOME_MENU_SETTINGS_PERFORMANCE_OVERLAY_ENABLE,
HOME_MENU_SETTINGS_PERFORMANCE_OVERLAY_ENABLE_FRAMERATE_GRAPH,

View file

@ -182,6 +182,7 @@ struct cfg_root : cfg::node
cfg::_bool disable_msl_fast_math{ this, "Disable MSL Fast Math", false };
cfg::_bool disable_async_host_memory_manager{ this, "Disable Asynchronous Memory Manager", false, true };
cfg::_enum<output_scaling_mode> output_scaling{ this, "Output Scaling Mode", output_scaling_mode::bilinear, true };
cfg::_bool record_with_overlays{ this, "Record With Overlays", true, true };
struct node_vk : cfg::node
{

View file

@ -241,6 +241,9 @@ void debugger_frame::closeEvent(QCloseEvent* event)
QDockWidget::closeEvent(event);
Q_EMIT DebugFrameClosed();
m_spu_disasm_memory.reset();
m_cpu.reset();
}
void debugger_frame::showEvent(QShowEvent* event)

View file

@ -108,6 +108,7 @@ enum class emu_settings_type
ForceHwMSAAResolve,
DisableAsyncHostMM,
UseReBAR,
RecordWithOverlays,
// Performance Overlay
PerfOverlayEnabled,
@ -311,6 +312,7 @@ inline static const std::map<emu_settings_type, cfg_location> settings_location
{ emu_settings_type::OutputScalingMode, { "Video", "Output Scaling Mode"}},
{ emu_settings_type::ForceHwMSAAResolve, { "Video", "Force Hardware MSAA Resolve"}},
{ emu_settings_type::DisableAsyncHostMM, { "Video", "Disable Asynchronous Memory Manager"}},
{ emu_settings_type::RecordWithOverlays, { "Video", "Record With Overlays"}},
// Vulkan
{ emu_settings_type::VulkanAsyncTextureUploads, { "Video", "Vulkan", "Asynchronous Texture Streaming 2"}},

View file

@ -830,10 +830,10 @@ bool gs_frame::can_consume_frame() const
return video_provider.can_consume_frame();
}
void gs_frame::present_frame(std::vector<u8>& data, u32 pitch, u32 width, u32 height, bool is_bgra) const
void gs_frame::present_frame(std::vector<u8>&& data, u32 pitch, u32 width, u32 height, bool is_bgra) const
{
utils::video_provider& video_provider = g_fxo->get<utils::video_provider>();
video_provider.present_frame(data, pitch, width, height, is_bgra);
video_provider.present_frame(std::move(data), pitch, width, height, is_bgra);
}
void gs_frame::take_screenshot(std::vector<u8>&& data, u32 sshot_width, u32 sshot_height, bool is_bgra)

View file

@ -79,7 +79,7 @@ public:
bool get_mouse_lock_state();
bool can_consume_frame() const override;
void present_frame(std::vector<u8>& data, u32 pitch, u32 width, u32 height, bool is_bgra) const override;
void present_frame(std::vector<u8>&& data, u32 pitch, u32 width, u32 height, bool is_bgra) const override;
void take_screenshot(std::vector<u8>&& data, u32 sshot_width, u32 sshot_height, bool is_bgra) override;
protected:

View file

@ -266,6 +266,7 @@ private:
case localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_SHOW_PRESSURE_INTENSITY_TOGGLE_HINT: return tr("Show Pressure Intensity Toggle Hint", "Overlays");
case localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_SHOW_ANALOG_LIMITER_TOGGLE_HINT: return tr( "Show Analog Limiter Toggle Hint", "Overlays");
case localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_SHOW_MOUSE_AND_KB_TOGGLE_HINT: return tr("Show Mouse And Keyboard Toggle Hint", "Overlays");
case localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_RECORD_WITH_OVERLAYS: return tr("Record With Overlays", "Overlays");
case localized_string_id::HOME_MENU_SETTINGS_PERFORMANCE_OVERLAY: return tr("Performance Overlay");
case localized_string_id::HOME_MENU_SETTINGS_PERFORMANCE_OVERLAY_ENABLE: return tr("Enable Performance Overlay", "Performance Overlay");
case localized_string_id::HOME_MENU_SETTINGS_PERFORMANCE_OVERLAY_ENABLE_FRAMERATE_GRAPH: return tr("Enable Framerate Graph", "Performance Overlay");

View file

@ -20,6 +20,7 @@
#include <QWheelEvent>
#include <QHoverEvent>
#include <QMouseEvent>
#include <QCloseEvent>
#include <QTimer>
#include <QThread>
#include <QKeyEvent>
@ -732,7 +733,7 @@ void* memory_viewer_panel::to_ptr(u32 addr, u32 size) const
}
case thread_class::spu:
{
if (size <= SPU_LS_SIZE && SPU_LS_SIZE - size >= (addr % SPU_LS_SIZE))
if (m_spu_shm && size <= SPU_LS_SIZE && SPU_LS_SIZE - size >= (addr % SPU_LS_SIZE))
{
return m_spu_shm->map_self() + (addr % SPU_LS_SIZE);
}
@ -961,6 +962,14 @@ void memory_viewer_panel::keyPressEvent(QKeyEvent* event)
QDialog::keyPressEvent(event);
}
void memory_viewer_panel::closeEvent(QCloseEvent* event)
{
event->accept();
m_spu_shm.reset();
m_disasm.reset();
m_get_cpu = [](){ return std::add_pointer_t<cpu_thread>{}; };
}
void memory_viewer_panel::ShowImage(QWidget* parent, u32 addr, color_format format, u32 width, u32 height, bool flipv) const
{
u32 texel_bytes = 4;

View file

@ -19,6 +19,7 @@ class QLabel;
class QThread;
class QHBoxLayout;
class QKeyEvent;
class QCloseEvent;
class cpu_thread;
class CPUDisAsm;
@ -95,10 +96,10 @@ private:
QHBoxLayout* m_hbox_mem_panel = nullptr;
QThread* m_search_thread = nullptr;
const std::function<cpu_thread*()> m_get_cpu;
std::function<cpu_thread*()> m_get_cpu;
const thread_class m_type;
const std::add_pointer_t<rsx::thread> m_rsx;
const std::shared_ptr<utils::shm> m_spu_shm;
std::shared_ptr<utils::shm> m_spu_shm;
const u32 m_addr_mask;
std::shared_ptr<CPUDisAsm> m_disasm;
@ -119,6 +120,7 @@ private:
u64 OnSearch(std::string wstr, u32 mode);
void keyPressEvent(QKeyEvent* event) override;
void closeEvent(QCloseEvent* event) override;
};
// Lifetime management with IDM

View file

@ -330,7 +330,17 @@ settings_dialog::settings_dialog(std::shared_ptr<gui_settings> gui_settings, std
));
}
if (QMessageBox::No == QMessageBox::critical(this, title, message, QMessageBox::Yes, QMessageBox::No))
QMessageBox mb;
mb.setWindowModality(Qt::WindowModal);
mb.setWindowTitle(title);
mb.setIcon(QMessageBox::Critical);
mb.setTextFormat(Qt::RichText);
mb.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
mb.setDefaultButton(QMessageBox::No);
mb.setText(message);
mb.layout()->setSizeConstraint(QLayout::SetFixedSize);
if (mb.exec() == QMessageBox::No)
{
// Reset if the messagebox was answered with no. This prevents the currentIndexChanged signal in EnhanceComboBox
ui->enableTSX->setCurrentIndex(find_item(ui->enableTSX, static_cast<int>(g_cfg.core.enable_TSX.def)));
@ -1873,15 +1883,16 @@ settings_dialog::settings_dialog(std::shared_ptr<gui_settings> gui_settings, std
SubscribeTooltip(ui->useNativeInterface, tooltips.settings.use_native_interface);
#if defined(__linux__)
ui->enableGamemode->setVisible(true);
#endif
#if defined(GAMEMODE_AVAILABLE)
ui->enableGamemode->setEnabled(true);
m_emu_settings->EnhanceCheckBox(ui->enableGamemode, emu_settings_type::EnableGamemode);
SubscribeTooltip(ui->enableGamemode, tooltips.settings.enable_gamemode);
#else
ui->enableGamemode->setEnabled(false);
SubscribeTooltip(ui->enableGamemode, tooltips.settings.no_gamemode);
#endif
#else
ui->enableGamemode->setVisible(false);
#endif
m_emu_settings->EnhanceCheckBox(ui->showShaderCompilationHint, emu_settings_type::ShowShaderCompilationHint);
SubscribeTooltip(ui->showShaderCompilationHint, tooltips.settings.show_shader_compilation_hint);
@ -1904,6 +1915,9 @@ settings_dialog::settings_dialog(std::shared_ptr<gui_settings> gui_settings, std
m_emu_settings->EnhanceCheckBox(ui->showCaptureHints, emu_settings_type::ShowCaptureHints);
SubscribeTooltip(ui->showCaptureHints, tooltips.settings.show_capture_hints);
m_emu_settings->EnhanceCheckBox(ui->recordWithOverlays, emu_settings_type::RecordWithOverlays);
SubscribeTooltip(ui->recordWithOverlays, tooltips.settings.record_with_overlays);
m_emu_settings->EnhanceCheckBox(ui->pauseDuringHomeMenu, emu_settings_type::PauseDuringHomeMenu);
SubscribeTooltip(ui->pauseDuringHomeMenu, tooltips.settings.pause_during_home_menu);

View file

@ -3067,14 +3067,15 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="recordWithOverlays">
<property name="text">
<string>Record with overlays</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="enableGamemode">
<property name="enabled">
<bool>false</bool>
</property>
<property name="visible">
<bool>false</bool>
</property>
<property name="text">
<string>Enable GameMode</string>
</property>

View file

@ -155,6 +155,7 @@ public:
const QString show_mouse_and_keyboard_toggle_hint = tr("Shows mouse and keyboard toggle hint using the native overlay.");
const QString show_capture_hints = tr("Shows screenshot and recording hints using the native overlay.");
const QString use_native_interface = tr("Enables use of native HUD within the game window that can interact with game controllers.\nWhen disabled, regular Qt dialogs are used instead.\nCurrently, the on-screen keyboard only supports the English key layout.");
const QString record_with_overlays = tr("Enables recording with overlays.\nThis also affects screenshots.");
const QString pause_during_home_menu = tr("When enabled, opening the home menu will also pause emulation.\nWhile most games pause themselves while the home menu is shown, some do not.\nIn that case it can be helpful to pause the emulation whenever the home menu is open.");
const QString perf_overlay_enabled = tr("Enables or disables the performance overlay.");

View file

@ -127,7 +127,7 @@ namespace utils
return pts > m_last_video_pts_incoming;
}
void video_provider::present_frame(std::vector<u8>& data, u32 pitch, u32 width, u32 height, bool is_bgra)
void video_provider::present_frame(std::vector<u8>&& data, u32 pitch, u32 width, u32 height, bool is_bgra)
{
if (!m_active)
{

View file

@ -21,7 +21,7 @@ namespace utils
void set_pause_time_us(usz pause_time_us);
bool can_consume_frame();
void present_frame(std::vector<u8>& data, u32 pitch, u32 width, u32 height, bool is_bgra);
void present_frame(std::vector<u8>&& data, u32 pitch, u32 width, u32 height, bool is_bgra);
void present_samples(const u8* buf, u32 sample_count, u16 channels);