From db4041e079f4707ed5d8e2d6786bcec215695569 Mon Sep 17 00:00:00 2001 From: Eladash Date: Mon, 16 Dec 2019 21:56:14 +0200 Subject: [PATCH] Implement rounded_div Round-to-nearest integral based division, optimized for unsigned integral. Used in sceNpTrophyGetGameProgress. Do not allow signed values for aligned_div(), align(). --- Utilities/types.h | 25 ++++++++++++++++++++++--- rpcs3/Emu/Cell/Modules/cellVdec.cpp | 4 +++- rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp | 5 +++-- rpcs3/Emu/RSX/Common/TextureUtils.cpp | 4 ++-- rpcs3/Emu/RSX/VK/VKCompute.h | 2 +- rpcs3/Emu/RSX/rsx_utils.h | 7 ------- 6 files changed, 31 insertions(+), 16 deletions(-) diff --git a/Utilities/types.h b/Utilities/types.h index 967da7475a..fb2a1e0c09 100644 --- a/Utilities/types.h +++ b/Utilities/types.h @@ -440,10 +440,29 @@ union alignas(2) f16 CHECK_SIZE_ALIGN(f16, 2, 2); -template ::value>> -constexpr T align(const T& value, ullong align) +template ::value && std::is_unsigned::value>> +constexpr T align(T value, ullong align) { - return static_cast((value + (align - 1)) & ~(align - 1)); + return static_cast((value + (align - 1)) & (0 - align)); +} + +// General purpose aligned division, the result is rounded up not truncated +template ::value && std::is_unsigned::value>> +constexpr T aligned_div(T value, ullong align) +{ + return static_cast((value + align - 1) / align); +} + +// General purpose aligned division, the result is rounded to nearest +template ::value>> +constexpr T rounded_div(T value, std::conditional_t::value, llong, ullong> align) +{ + if constexpr (std::is_unsigned::value) + { + return static_cast((value + (align / 2)) / align); + } + + return static_cast((value + (value < 0 ? 0 - align : align) / 2) / align); } template diff --git a/rpcs3/Emu/Cell/Modules/cellVdec.cpp b/rpcs3/Emu/Cell/Modules/cellVdec.cpp index 033da2f91a..07f596335c 100644 --- a/rpcs3/Emu/Cell/Modules/cellVdec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellVdec.cpp @@ -769,7 +769,9 @@ error_code cellVdecGetPicItem(u32 handle, vm::pptr picItem) info->codecType = vdec->type; info->startAddr = 0x00000123; // invalid value (no address for picture) - info->size = align(av_image_get_buffer_size(vdec->ctx->pix_fmt, vdec->ctx->width, vdec->ctx->height, 1), 128); + const int buffer_size = av_image_get_buffer_size(vdec->ctx->pix_fmt, vdec->ctx->width, vdec->ctx->height, 1); + verify(HERE), (buffer_size >= 0); + info->size = align(buffer_size, 128); info->auNum = 1; info->auPts[0].lower = static_cast(pts); info->auPts[0].upper = static_cast(pts >> 32); diff --git a/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp b/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp index 0618269212..7d76a8a8e5 100644 --- a/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp @@ -929,8 +929,9 @@ error_code sceNpTrophyGetGameProgress(u32 context, u32 handle, vm::ptr perc const u32 trp_count = ctxt->tropusr->GetTrophiesCount(); verify(HERE), trp_count > 0 && trp_count <= 128; - - *percentage = static_cast(std::lround((unlocked * 100.) / trp_count)); + + // Round result to nearest + *percentage = rounded_div(unlocked * 100, trp_count); return CELL_OK; } diff --git a/rpcs3/Emu/RSX/Common/TextureUtils.cpp b/rpcs3/Emu/RSX/Common/TextureUtils.cpp index d74236a6ba..cfa17f7974 100644 --- a/rpcs3/Emu/RSX/Common/TextureUtils.cpp +++ b/rpcs3/Emu/RSX/Common/TextureUtils.cpp @@ -364,8 +364,8 @@ namespace } else { - current_subresource_layout.width_in_block = rsx::aligned_div(miplevel_width_in_texel, block_edge_in_texel); - current_subresource_layout.height_in_block = rsx::aligned_div(miplevel_height_in_texel, block_edge_in_texel); + current_subresource_layout.width_in_block = aligned_div(miplevel_width_in_texel, block_edge_in_texel); + current_subresource_layout.height_in_block = aligned_div(miplevel_height_in_texel, block_edge_in_texel); } if (padded_row) diff --git a/rpcs3/Emu/RSX/VK/VKCompute.h b/rpcs3/Emu/RSX/VK/VKCompute.h index 25b2a6d611..dc48cd343b 100644 --- a/rpcs3/Emu/RSX/VK/VKCompute.h +++ b/rpcs3/Emu/RSX/VK/VKCompute.h @@ -779,7 +779,7 @@ namespace vk set_parameters(cmd); const u32 num_bytes_per_invocation = (sizeof(_BlockType) * optimal_group_size); - const u32 linear_invocations = rsx::aligned_div(data_length, num_bytes_per_invocation); + const u32 linear_invocations = aligned_div(data_length, num_bytes_per_invocation); compute_task::run(cmd, linear_invocations); } }; diff --git a/rpcs3/Emu/RSX/rsx_utils.h b/rpcs3/Emu/RSX/rsx_utils.h index f4d635b971..37898354ad 100644 --- a/rpcs3/Emu/RSX/rsx_utils.h +++ b/rpcs3/Emu/RSX/rsx_utils.h @@ -277,13 +277,6 @@ namespace rsx return ((value + alignment - 1) / alignment) * alignment; } - // General purpose aligned division, the result is rounded up not truncated - template - static inline T aligned_div(T value, U alignment) - { - return (value + alignment - 1) / alignment; - } - // Copy memory in inverse direction from source // Used to scale negatively x axis while transfering image data template