This commit is contained in:
aenu
2025-06-19 19:26:23 +08:00
parent 12a6d7050a
commit d4afc2e03e
28 changed files with 892 additions and 226 deletions

View File

@@ -15,6 +15,8 @@
android:icon="@drawable/app_icon"
android:isGame="true">
<activity android:name="aenu.aps3e.MainActivity"
android:launchMode="singleTask"
android:configChanges="layoutDirection|locale|orientation|uiMode|screenLayout|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"
android:exported="true"
android:label="@string/app_name">
<intent-filter>

View File

@@ -124,6 +124,8 @@ Video:
Output Scaling Mode: Bilinear
Vertex Buffer Upload Mode: Auto
Texture Upload Mode: CPU
Use BGRA Format: true
Force Convert Texture: false
Vulkan:
Adapter: ""
Force FIFO present mode: true
@@ -205,7 +207,7 @@ System:
Language: English (US)
Keyboard Type: English keyboard (US standard)
Enter button assignment: Enter with cross
System Name: RPCS3-824
System Name: RPCS3-955
PSID high: 0
PSID low: 0
HDD Model Name: ""

View File

@@ -1946,7 +1946,6 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved){
static std::unique_ptr<logs::listener> log_file;
{
//log_file = logs::make_file_listener(std::string(getenv("APS3E_LOG_DIR"))+"/rp3_log.txt", 1024*1024*1024);
}
}

View File

@@ -233,6 +233,8 @@ static const std::string gen_skips[]={
"Miscellaneous|GDB Server",
"Miscellaneous|Window Title Format",
"Video|Force Convert Texture"
"Video|Performance Overlay|Font",
"Video|Performance Overlay|Body Color (hex)",
"Video|Performance Overlay|Body Background (hex)",
@@ -263,7 +265,7 @@ static jstring generate_config_xml(JNIEnv* env,jobject self){
break;
case cfg::type::_int:
case cfg::type::uint:
out<<"<SeekBarPreference app:title=\"@string/emulator_settings_"<<parent_name_l<<"_"<<key<<"\" \n";
out<<"<aenu.preference.SeekbarPreference app:title=\"@string/emulator_settings_"<<parent_name_l<<"_"<<key<<"\" \n";
out<<"app:min=\""<<node->get_min()<<"\"\n";
if(node->get_max()!=-1)
out<<"android:max=\""<<node->get_max()<<"\"\n";

View File

@@ -6,17 +6,17 @@
// MIT LICENSE
// ===========
// Copyright (c) 2022 Sergii Kudlai
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -31,6 +31,7 @@
#include <util/types.hpp>
template <bool BGRA>
static void bcdec__color_block(const u8* compressedBlock, u8* dstColors, int destinationPitch, bool onlyOpaqueMode) {
u16 c0, c1;
u32 refColors[4]; /* 0xAABBGGRR */
@@ -53,13 +54,23 @@ static void bcdec__color_block(const u8* compressedBlock, u8* dstColors, int des
r = (r0 * 527 + 23) >> 6;
g = (g0 * 259 + 33) >> 6;
b = (b0 * 527 + 23) >> 6;
refColors[0] = 0xFF000000 | (b << 16) | (g << 8) | r;
if constexpr (BGRA) {
refColors[0] = 0xFF000000 | (r << 16) | (g << 8) | b;
}
else {
refColors[0] = 0xFF000000 | (b << 16) | (g << 8) | r;
}
r = (r1 * 527 + 23) >> 6;
g = (g1 * 259 + 33) >> 6;
b = (b1 * 527 + 23) >> 6;
refColors[1] = 0xFF000000 | (b << 16) | (g << 8) | r;
if constexpr (BGRA) {
refColors[1] = 0xFF000000 | (r << 16) | (g << 8) | b;
}
else {
refColors[1] = 0xFF000000 | (b << 16) | (g << 8) | r;
}
if (c0 > c1 || onlyOpaqueMode)
{ /* Standard BC1 mode (also BC3 color block uses ONLY this mode) */
/* color_2 = 2/3*color_0 + 1/3*color_1
@@ -67,12 +78,23 @@ static void bcdec__color_block(const u8* compressedBlock, u8* dstColors, int des
r = ((2 * r0 + r1) * 351 + 61) >> 7;
g = ((2 * g0 + g1) * 2763 + 1039) >> 11;
b = ((2 * b0 + b1) * 351 + 61) >> 7;
refColors[2] = 0xFF000000 | (b << 16) | (g << 8) | r;
if constexpr (BGRA) {
refColors[2] = 0xFF000000 | (r << 16) | (g << 8) | b;
}
else {
refColors[2] = 0xFF000000 | (b << 16) | (g << 8) | r;
}
r = ((r0 + r1 * 2) * 351 + 61) >> 7;
g = ((g0 + g1 * 2) * 2763 + 1039) >> 11;
b = ((b0 + b1 * 2) * 351 + 61) >> 7;
refColors[3] = 0xFF000000 | (b << 16) | (g << 8) | r;
if constexpr (BGRA) {
refColors[3] = 0xFF000000 | (r << 16) | (g << 8) | b;
}
else {
refColors[3] = 0xFF000000 | (b << 16) | (g << 8) | r;
}
}
else
{ /* Quite rare BC1A mode */
@@ -81,7 +103,11 @@ static void bcdec__color_block(const u8* compressedBlock, u8* dstColors, int des
r = ((r0 + r1) * 1053 + 125) >> 8;
g = ((g0 + g1) * 4145 + 1019) >> 11;
b = ((b0 + b1) * 1053 + 125) >> 8;
refColors[2] = 0xFF000000 | (b << 16) | (g << 8) | r;
if constexpr (BGRA) {
refColors[2] = 0xFF000000 | (r << 16) | (g << 8) | b;
} else{
refColors[2] = 0xFF000000 | (b << 16) | (g << 8) | r;
}
refColors[3] = 0x00000000;
}
@@ -154,17 +180,20 @@ static void bcdec__smooth_alpha_block(const u8* compressedBlock, u8* decompresse
}
}
template <bool BGRA>
static inline void bcdec_bc1(const u8* compressedBlock, u8* decompressedBlock, int destinationPitch) {
bcdec__color_block(compressedBlock, decompressedBlock, destinationPitch, false);
bcdec__color_block<BGRA>(compressedBlock, decompressedBlock, destinationPitch, false);
}
template <bool BGRA>
static inline void bcdec_bc2(const u8* compressedBlock, u8* decompressedBlock, int destinationPitch) {
bcdec__color_block(compressedBlock + 8, decompressedBlock, destinationPitch, true);
bcdec__color_block<BGRA>(compressedBlock + 8, decompressedBlock, destinationPitch, true);
bcdec__sharp_alpha_block(reinterpret_cast<const u16*>(compressedBlock), decompressedBlock + 3, destinationPitch);
}
template <bool BGRA>
static inline void bcdec_bc3(const u8* compressedBlock, u8* decompressedBlock, int destinationPitch) {
bcdec__color_block(compressedBlock + 8, decompressedBlock, destinationPitch, true);
bcdec__color_block<BGRA>(compressedBlock + 8, decompressedBlock, destinationPitch, true);
bcdec__smooth_alpha_block(compressedBlock, decompressedBlock + 3, destinationPitch);
}

View File

@@ -456,7 +456,7 @@ struct copy_linear_block_to_vtc
struct copy_decoded_rb_rg_block
{
template <bool SwapWords = false, typename T>
template <bool UseBGRA,bool SwapWords, typename T>
static void copy_mipmap_level(std::span<u32> dst, std::span<const T> src, u16 width_in_block, u16 row_count, u16 depth, u32 dst_pitch_in_block, u32 src_pitch_in_block)
{
static_assert(sizeof(T) == 4, "Type size doesn't match.");
@@ -490,9 +490,13 @@ struct copy_decoded_rb_rg_block
red1 = (data >> 16) & 0XFF;
green = (data >> 24) & 0xFF;
}
dst[dst_offset + (col * 2)] = (red0 << 0)|(green << 8)|(blue<< 16) | (0xFF << 24);
dst[dst_offset + (col * 2 + 1)] = (red1 << 0)|(green << 8)|(blue<< 16) | (0xFF << 24);
if constexpr(!UseBGRA) {
dst[dst_offset + (col * 2)] = (red0 << 0) | (green << 8) | (blue << 16) | (0xFF << 24);
dst[dst_offset + (col * 2 + 1)] = (red1 << 0) | (green << 8) | (blue << 16) | (0xFF << 24);
}else{
dst[dst_offset + (col * 2)] = (blue << 0) | (green << 8) | (red0 << 16) | (0xFF << 24);
dst[dst_offset + (col * 2 + 1)] = (blue << 0) | (green << 8) | (red1 << 16) | (0xFF << 24);
}
}
src_offset += src_pitch_in_block;
@@ -562,62 +566,65 @@ struct copy_rgb655_block_swizzled
struct copy_decoded_bc1_block
{
static void copy_mipmap_level(std::span<u32> dst, std::span<const u64> src, u16 width_in_block, u32 row_count, u16 depth, u32 dst_pitch_in_block, u32 src_pitch_in_block)
{
u32 src_offset = 0, dst_offset = 0, destinationPitch = dst_pitch_in_block * 4;
for (u32 row = 0; row < row_count * depth; row++)
{
for (u32 col = 0; col < width_in_block; col++)
{
const u8* compressedBlock = reinterpret_cast<const u8*>(&src[src_offset + col]);
u8* decompressedBlock = reinterpret_cast<u8*>(&dst[dst_offset + col * 4]);
bcdec_bc1(compressedBlock, decompressedBlock, destinationPitch);
}
template<bool BGRA>
static void copy_mipmap_level(std::span<u32> dst, std::span<const u64> src, u16 width_in_block, u32 row_count, u16 depth, u32 dst_pitch_in_block, u32 src_pitch_in_block)
{
u32 src_offset = 0, dst_offset = 0, destinationPitch = dst_pitch_in_block * 4;
for (u32 row = 0; row < row_count * depth; row++)
{
for (u32 col = 0; col < width_in_block; col++)
{
const u8* compressedBlock = reinterpret_cast<const u8*>(&src[src_offset + col]);
u8* decompressedBlock = reinterpret_cast<u8*>(&dst[dst_offset + col * 4]);
bcdec_bc1<BGRA>(compressedBlock, decompressedBlock, destinationPitch);
}
src_offset += src_pitch_in_block;
dst_offset += destinationPitch;
}
}
src_offset += src_pitch_in_block;
dst_offset += destinationPitch;
}
}
};
struct copy_decoded_bc2_block
{
static void copy_mipmap_level(std::span<u32> dst, std::span<const u128> src, u16 width_in_block, u32 row_count, u16 depth, u32 dst_pitch_in_block, u32 src_pitch_in_block)
{
u32 src_offset = 0, dst_offset = 0, destinationPitch = dst_pitch_in_block * 4;
for (u32 row = 0; row < row_count * depth; row++)
{
for (u32 col = 0; col < width_in_block; col++)
{
const u8* compressedBlock = reinterpret_cast<const u8*>(&src[src_offset + col]);
u8* decompressedBlock = reinterpret_cast<u8*>(&dst[dst_offset + col * 4]);
bcdec_bc2(compressedBlock, decompressedBlock, destinationPitch);
}
template<bool BGRA>
static void copy_mipmap_level(std::span<u32> dst, std::span<const u128> src, u16 width_in_block, u32 row_count, u16 depth, u32 dst_pitch_in_block, u32 src_pitch_in_block)
{
u32 src_offset = 0, dst_offset = 0, destinationPitch = dst_pitch_in_block * 4;
for (u32 row = 0; row < row_count * depth; row++)
{
for (u32 col = 0; col < width_in_block; col++)
{
const u8* compressedBlock = reinterpret_cast<const u8*>(&src[src_offset + col]);
u8* decompressedBlock = reinterpret_cast<u8*>(&dst[dst_offset + col * 4]);
bcdec_bc2<BGRA>(compressedBlock, decompressedBlock, destinationPitch);
}
src_offset += src_pitch_in_block;
dst_offset += destinationPitch;
}
}
src_offset += src_pitch_in_block;
dst_offset += destinationPitch;
}
}
};
struct copy_decoded_bc3_block
{
static void copy_mipmap_level(std::span<u32> dst, std::span<const u128> src, u16 width_in_block, u32 row_count, u16 depth, u32 dst_pitch_in_block, u32 src_pitch_in_block)
{
u32 src_offset = 0, dst_offset = 0, destinationPitch = dst_pitch_in_block * 4;
for (u32 row = 0; row < row_count * depth; row++)
{
for (u32 col = 0; col < width_in_block; col++)
{
const u8* compressedBlock = reinterpret_cast<const u8*>(&src[src_offset + col]);
u8* decompressedBlock = reinterpret_cast<u8*>(&dst[dst_offset + col * 4]);
bcdec_bc3(compressedBlock, decompressedBlock, destinationPitch);
}
template<bool BGRA>
static void copy_mipmap_level(std::span<u32> dst, std::span<const u128> src, u16 width_in_block, u32 row_count, u16 depth, u32 dst_pitch_in_block, u32 src_pitch_in_block)
{
u32 src_offset = 0, dst_offset = 0, destinationPitch = dst_pitch_in_block * 4;
for (u32 row = 0; row < row_count * depth; row++)
{
for (u32 col = 0; col < width_in_block; col++)
{
const u8* compressedBlock = reinterpret_cast<const u8*>(&src[src_offset + col]);
u8* decompressedBlock = reinterpret_cast<u8*>(&dst[dst_offset + col * 4]);
bcdec_bc3<BGRA>(compressedBlock, decompressedBlock, destinationPitch);
}
src_offset += src_pitch_in_block;
dst_offset += destinationPitch;
}
}
src_offset += src_pitch_in_block;
dst_offset += destinationPitch;
}
}
};
namespace
@@ -937,6 +944,10 @@ namespace rsx
int words_per_block;
u32 dst_pitch_in_block;
static const bool use_bgra_fmt=g_cfg.video.bgra_format.get();
constexpr bool _BGRA=true;
constexpr bool _RGBA=false;
switch (format)
{
case CELL_GCM_TEXTURE_B8:
@@ -956,14 +967,20 @@ namespace rsx
case CELL_GCM_TEXTURE_COMPRESSED_B8R8_G8R8:
{
copy_decoded_rb_rg_block::copy_mipmap_level<true>(dst_buffer.as_span<u32>(), src_layout.data.as_span<const u32>(), w, h, depth, get_row_pitch_in_block<u32>(src_layout.width_in_texel, caps.alignment), src_layout.pitch_in_block);
break;
if(use_bgra_fmt)
copy_decoded_rb_rg_block::copy_mipmap_level<_BGRA,true>(dst_buffer.as_span<u32>(), src_layout.data.as_span<const u32>(), w, h, depth, get_row_pitch_in_block<u32>(src_layout.width_in_texel, caps.alignment), src_layout.pitch_in_block);
else
copy_decoded_rb_rg_block::copy_mipmap_level<_RGBA,true>(dst_buffer.as_span<u32>(), src_layout.data.as_span<const u32>(), w, h, depth, get_row_pitch_in_block<u32>(src_layout.width_in_texel, caps.alignment), src_layout.pitch_in_block);
break;
}
case CELL_GCM_TEXTURE_COMPRESSED_R8B8_R8G8:
{
copy_decoded_rb_rg_block::copy_mipmap_level(dst_buffer.as_span<u32>(), src_layout.data.as_span<const u32>(), w, h, depth, get_row_pitch_in_block<u32>(src_layout.width_in_texel, caps.alignment), src_layout.pitch_in_block);
break;
if(use_bgra_fmt)
copy_decoded_rb_rg_block::copy_mipmap_level<_BGRA,false>(dst_buffer.as_span<u32>(), src_layout.data.as_span<const u32>(), w, h, depth, get_row_pitch_in_block<u32>(src_layout.width_in_texel, caps.alignment), src_layout.pitch_in_block);
else
copy_decoded_rb_rg_block::copy_mipmap_level<_RGBA,false>(dst_buffer.as_span<u32>(), src_layout.data.as_span<const u32>(), w, h, depth, get_row_pitch_in_block<u32>(src_layout.width_in_texel, caps.alignment), src_layout.pitch_in_block);
break;
}
#ifndef __APPLE__
@@ -1052,16 +1069,17 @@ namespace rsx
case CELL_GCM_TEXTURE_A8R8G8B8:
case CELL_GCM_TEXTURE_D8R8G8B8:
{
if (is_swizzled)
copy_u32_ror8_block_swizzled::copy_mipmap_level(dst_buffer.as_span<u32>(), src_layout.data.as_span<const u32>()
, w, h, depth, src_layout.border, get_row_pitch_in_block<u32>(w, caps.alignment), src_layout.pitch_in_block);
if(!use_bgra_fmt){
if (is_swizzled)
copy_u32_ror8_block_swizzled::copy_mipmap_level(dst_buffer.as_span<u32>(), src_layout.data.as_span<const u32>()
, w, h, depth, src_layout.border, get_row_pitch_in_block<u32>(w, caps.alignment), src_layout.pitch_in_block);
else
copy_u32_ror8_block::copy_mipmap_level(dst_buffer.as_span<u32>(), src_layout.data.as_span<const u32>()
, w, h, depth, src_layout.border, get_row_pitch_in_block<u32>(w, caps.alignment), src_layout.pitch_in_block);
break;
}
else
copy_u32_ror8_block::copy_mipmap_level(dst_buffer.as_span<u32>(), src_layout.data.as_span<const u32>()
, w, h, depth, src_layout.border, get_row_pitch_in_block<u32>(w, caps.alignment), src_layout.pitch_in_block);
break;
}
[[fallthrough]];
case CELL_GCM_TEXTURE_DEPTH24_D8:
case CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT: // Untested
{
@@ -1115,8 +1133,11 @@ namespace rsx
{
if (!caps.supports_dxt)
{
copy_decoded_bc1_block::copy_mipmap_level(dst_buffer.as_span<u32>(), src_layout.data.as_span<const u64>(), w, h, depth, get_row_pitch_in_block<u32>(w, caps.alignment), src_layout.pitch_in_block);
break;
if(use_bgra_fmt)
copy_decoded_bc1_block::copy_mipmap_level<_BGRA>(dst_buffer.as_span<u32>(), src_layout.data.as_span<const u64>(), w, h, depth, get_row_pitch_in_block<u32>(w, caps.alignment), src_layout.pitch_in_block);
else
copy_decoded_bc1_block::copy_mipmap_level<_RGBA>(dst_buffer.as_span<u32>(), src_layout.data.as_span<const u64>(), w, h, depth, get_row_pitch_in_block<u32>(w, caps.alignment), src_layout.pitch_in_block);
break;
}
const bool is_3d = depth > 1;
@@ -1146,8 +1167,11 @@ namespace rsx
{
if (!caps.supports_dxt)
{
copy_decoded_bc2_block::copy_mipmap_level(dst_buffer.as_span<u32>(), src_layout.data.as_span<const u128>(), w, h, depth, get_row_pitch_in_block<u32>(w, caps.alignment), src_layout.pitch_in_block);
break;
if(use_bgra_fmt)
copy_decoded_bc2_block::copy_mipmap_level<_BGRA>(dst_buffer.as_span<u32>(), src_layout.data.as_span<const u128>(), w, h, depth, get_row_pitch_in_block<u32>(w, caps.alignment), src_layout.pitch_in_block);
else
copy_decoded_bc2_block::copy_mipmap_level<_RGBA>(dst_buffer.as_span<u32>(), src_layout.data.as_span<const u128>(), w, h, depth, get_row_pitch_in_block<u32>(w, caps.alignment), src_layout.pitch_in_block);
break;
}
[[fallthrough]];
}
@@ -1155,8 +1179,11 @@ namespace rsx
{
if (!caps.supports_dxt)
{
copy_decoded_bc3_block::copy_mipmap_level(dst_buffer.as_span<u32>(), src_layout.data.as_span<const u128>(), w, h, depth, get_row_pitch_in_block<u32>(w, caps.alignment), src_layout.pitch_in_block);
break;
if(use_bgra_fmt)
copy_decoded_bc3_block::copy_mipmap_level<_BGRA>(dst_buffer.as_span<u32>(), src_layout.data.as_span<const u128>(), w, h, depth, get_row_pitch_in_block<u32>(w, caps.alignment), src_layout.pitch_in_block);
else
copy_decoded_bc3_block::copy_mipmap_level<_RGBA>(dst_buffer.as_span<u32>(), src_layout.data.as_span<const u128>(), w, h, depth, get_row_pitch_in_block<u32>(w, caps.alignment), src_layout.pitch_in_block);
break;
}
const bool is_3d = depth > 1;
@@ -1207,6 +1234,8 @@ namespace rsx
int words_per_block;
u32 dst_pitch_in_block;
static const bool use_bgra_fmt=g_cfg.video.bgra_format.get();
switch (format)
{
case CELL_GCM_TEXTURE_B8:
@@ -1339,16 +1368,18 @@ namespace rsx
case CELL_GCM_TEXTURE_A8R8G8B8:
case CELL_GCM_TEXTURE_D8R8G8B8:
{
result.element_size=4;
result.block_length=1;
result.require_mth=texture_memory_info_require_mth::upload|texture_memory_info_require_mth::ror8_u32;
if (is_swizzled)
result.require_mth|=texture_memory_info_require_mth::deswizzle;
if(!use_bgra_fmt){
result.element_size=4;
result.block_length=1;
result.require_mth=texture_memory_info_require_mth::upload|texture_memory_info_require_mth::ror8_u32;
if (is_swizzled)
result.require_mth|=texture_memory_info_require_mth::deswizzle;
result.deferred_cmds= build_transfer_cmds(src_layout.data.data(),4*1,w,h,depth,src_layout.border,get_row_pitch_in_block<u32>(w, caps.alignment),src_layout.pitch_in_block);
break;
}
result.deferred_cmds= build_transfer_cmds(src_layout.data.data(),4*1,w,h,depth,src_layout.border,get_row_pitch_in_block<u32>(w, caps.alignment),src_layout.pitch_in_block);
break;
}
[[fallthrough]];
case CELL_GCM_TEXTURE_DEPTH24_D8:
case CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT: // Untested
{

View File

@@ -138,8 +138,8 @@ void main()
ocol = texture(fs1, vec3(tc0.x, fract(tc0.y), trunc(tc0.y))).rrrr * diff_color;
break;
case SAMPLER_MODE_TEXTURE2D:
#ifdef VULKAN
ocol = sample_image(fs0, tc0, blur_intensity).rgba * diff_color;
#ifdef USE_BGRA
ocol = sample_image(fs0, tc0, blur_intensity).bgra * diff_color;
#else
ocol = sample_image(fs0, tc0, blur_intensity).rgba * diff_color;
#endif

View File

@@ -65,7 +65,7 @@ namespace vk
if (!initialized)
{
init_descriptors();
#if !defined(__ANDROID__)
switch (vk::get_driver_vendor())
{
case vk::driver_vendor::unknown:
@@ -109,13 +109,7 @@ namespace vk
const auto& gpu = vk::g_render_device->gpu();
max_invocations_x = gpu.get_limits().maxComputeWorkGroupCount[0];
#else
unroll_loops = true;
optimal_kernel_size = 1;
const auto& gpu = vk::g_render_device->gpu();
max_invocations_x = gpu.get_limits().maxComputeWorkGroupCount[0];
optimal_group_size = gpu.get_limits().maxComputeWorkGroupSize[0]/4;
#endif
initialized = true;
}
}

View File

@@ -194,18 +194,20 @@ namespace vk
VkFormat get_compatible_sampler_format(const gpu_formats_support& support, u32 format)
{
const bool supports_dxt = vk::get_current_renderer()->get_texture_compression_bc_support();
static const bool supports_dxt = vk::get_current_renderer()->get_texture_compression_bc_support();
static const VkFormat default_sampler_format=g_cfg.video.bgra_format.get()?VK_FORMAT_B8G8R8A8_UNORM:VK_FORMAT_R8G8B8A8_UNORM;
switch (format)
{
#ifndef __APPLE__
case CELL_GCM_TEXTURE_R5G6B5: return VK_FORMAT_R5G6B5_UNORM_PACK16;
case CELL_GCM_TEXTURE_R6G5B5: return VK_FORMAT_R5G6B5_UNORM_PACK16; // Expand, discard high bit?
case CELL_GCM_TEXTURE_R5G5B5A1: return VK_FORMAT_R5G5B5A1_UNORM_PACK16;
case CELL_GCM_TEXTURE_D1R5G5B5: return VK_FORMAT_A1R5G5B5_UNORM_PACK16;
case CELL_GCM_TEXTURE_A1R5G5B5: return VK_FORMAT_A1R5G5B5_UNORM_PACK16;
case CELL_GCM_TEXTURE_A4R4G4B4: return VK_FORMAT_R4G4B4A4_UNORM_PACK16;
case CELL_GCM_TEXTURE_R5G6B5: return VK_FORMAT_R5G6B5_UNORM_PACK16;
case CELL_GCM_TEXTURE_R6G5B5: return VK_FORMAT_R5G6B5_UNORM_PACK16; // Expand, discard high bit?
case CELL_GCM_TEXTURE_R5G5B5A1: return VK_FORMAT_R5G5B5A1_UNORM_PACK16;
case CELL_GCM_TEXTURE_D1R5G5B5: return VK_FORMAT_A1R5G5B5_UNORM_PACK16;
case CELL_GCM_TEXTURE_A1R5G5B5: return VK_FORMAT_A1R5G5B5_UNORM_PACK16;
case CELL_GCM_TEXTURE_A4R4G4B4: return VK_FORMAT_R4G4B4A4_UNORM_PACK16;
#else
// assign B8G8R8A8_UNORM to formats that are not supported by Metal
// assign B8G8R8A8_UNORM to formats that are not supported by Metal
case CELL_GCM_TEXTURE_R6G5B5: return VK_FORMAT_B8G8R8A8_UNORM;
case CELL_GCM_TEXTURE_R5G6B5: return VK_FORMAT_B8G8R8A8_UNORM;
case CELL_GCM_TEXTURE_R5G5B5A1: return VK_FORMAT_B8G8R8A8_UNORM;
@@ -213,11 +215,12 @@ namespace vk
case CELL_GCM_TEXTURE_A1R5G5B5: return VK_FORMAT_B8G8R8A8_UNORM;
case CELL_GCM_TEXTURE_A4R4G4B4: return VK_FORMAT_B8G8R8A8_UNORM;
#endif
case CELL_GCM_TEXTURE_B8: return VK_FORMAT_R8_UNORM;
case CELL_GCM_TEXTURE_A8R8G8B8: return VK_FORMAT_R8G8B8A8_UNORM;
case CELL_GCM_TEXTURE_COMPRESSED_DXT1: return supports_dxt ? VK_FORMAT_BC1_RGBA_UNORM_BLOCK : VK_FORMAT_R8G8B8A8_UNORM;
case CELL_GCM_TEXTURE_COMPRESSED_DXT23: return supports_dxt ? VK_FORMAT_BC2_UNORM_BLOCK : VK_FORMAT_R8G8B8A8_UNORM;
case CELL_GCM_TEXTURE_COMPRESSED_DXT45: return supports_dxt ? VK_FORMAT_BC3_UNORM_BLOCK : VK_FORMAT_R8G8B8A8_UNORM;
case CELL_GCM_TEXTURE_A8R8G8B8: return default_sampler_format;
case CELL_GCM_TEXTURE_COMPRESSED_DXT1: return supports_dxt ? VK_FORMAT_BC1_RGBA_UNORM_BLOCK : default_sampler_format;
case CELL_GCM_TEXTURE_COMPRESSED_DXT23: return supports_dxt ? VK_FORMAT_BC2_UNORM_BLOCK : default_sampler_format;
case CELL_GCM_TEXTURE_COMPRESSED_DXT45: return supports_dxt ? VK_FORMAT_BC3_UNORM_BLOCK : default_sampler_format;
case CELL_GCM_TEXTURE_G8B8: return VK_FORMAT_R8G8_UNORM;
case CELL_GCM_TEXTURE_DEPTH24_D8: return support.d24_unorm_s8? VK_FORMAT_D24_UNORM_S8_UINT : VK_FORMAT_D32_SFLOAT_S8_UINT;
case CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT: return VK_FORMAT_D32_SFLOAT_S8_UINT;
@@ -229,11 +232,11 @@ namespace vk
case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT: return VK_FORMAT_R16G16B16A16_SFLOAT;
case CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT: return VK_FORMAT_R32G32B32A32_SFLOAT;
case CELL_GCM_TEXTURE_X32_FLOAT: return VK_FORMAT_R32_SFLOAT;
case CELL_GCM_TEXTURE_D8R8G8B8: return VK_FORMAT_R8G8B8A8_UNORM;
case CELL_GCM_TEXTURE_D8R8G8B8: return default_sampler_format;
case CELL_GCM_TEXTURE_COMPRESSED_HILO8: return VK_FORMAT_R8G8_UNORM;
case CELL_GCM_TEXTURE_COMPRESSED_HILO_S8: return VK_FORMAT_R8G8_SNORM;
case CELL_GCM_TEXTURE_COMPRESSED_B8R8_G8R8: return VK_FORMAT_R8G8B8A8_UNORM;
case CELL_GCM_TEXTURE_COMPRESSED_R8B8_R8G8: return VK_FORMAT_R8G8B8A8_UNORM;
case CELL_GCM_TEXTURE_COMPRESSED_B8R8_G8R8: return default_sampler_format;
case CELL_GCM_TEXTURE_COMPRESSED_R8B8_R8G8: return default_sampler_format;
default:
break;
}

View File

@@ -33,19 +33,21 @@ namespace vk
const VkComponentMapping o_rgb = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_ONE };
const VkComponentMapping z_rgb = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_ZERO };
static const bool use_bgra8_fmt=g_cfg.video.bgra_format.get();
switch (color_format)
{
#ifndef __APPLE__
case rsx::surface_color_format::r5g6b5:
return std::make_pair(VK_FORMAT_R5G6B5_UNORM_PACK16, vk::default_component_map);
case rsx::surface_color_format::r5g6b5:
return std::make_pair(VK_FORMAT_R5G6B5_UNORM_PACK16, vk::default_component_map);
case rsx::surface_color_format::x1r5g5b5_o1r5g5b5:
return std::make_pair(VK_FORMAT_A1R5G5B5_UNORM_PACK16, o_rgb);
case rsx::surface_color_format::x1r5g5b5_o1r5g5b5:
return std::make_pair(VK_FORMAT_A1R5G5B5_UNORM_PACK16, o_rgb);
case rsx::surface_color_format::x1r5g5b5_z1r5g5b5:
return std::make_pair(VK_FORMAT_A1R5G5B5_UNORM_PACK16, z_rgb);
case rsx::surface_color_format::x1r5g5b5_z1r5g5b5:
return std::make_pair(VK_FORMAT_A1R5G5B5_UNORM_PACK16, z_rgb);
#else
// assign B8G8R8A8_UNORM to formats that are not supported by Metal
// assign B8G8R8A8_UNORM to formats that are not supported by Metal
case rsx::surface_color_format::r5g6b5:
return std::make_pair(VK_FORMAT_B8G8R8A8_UNORM, vk::default_component_map);
@@ -56,22 +58,22 @@ namespace vk
return std::make_pair(VK_FORMAT_B8G8R8A8_UNORM, z_rgb);
#endif
case rsx::surface_color_format::a8r8g8b8:
return std::make_pair(VK_FORMAT_R8G8B8A8_UNORM, vk::default_component_map);
return std::make_pair(use_bgra8_fmt?VK_FORMAT_B8G8R8A8_UNORM:VK_FORMAT_R8G8B8A8_UNORM, vk::default_component_map);
case rsx::surface_color_format::a8b8g8r8:
return std::make_pair(VK_FORMAT_B8G8R8A8_UNORM, vk::default_component_map);
return std::make_pair(use_bgra8_fmt?VK_FORMAT_R8G8B8A8_UNORM:VK_FORMAT_B8G8R8A8_UNORM, vk::default_component_map);
case rsx::surface_color_format::x8b8g8r8_o8b8g8r8:
return std::make_pair(VK_FORMAT_B8G8R8A8_UNORM, o_rgb);
return std::make_pair(use_bgra8_fmt?VK_FORMAT_R8G8B8A8_UNORM:VK_FORMAT_B8G8R8A8_UNORM, o_rgb);
case rsx::surface_color_format::x8b8g8r8_z8b8g8r8:
return std::make_pair(VK_FORMAT_B8G8R8A8_UNORM, z_rgb);
return std::make_pair(use_bgra8_fmt?VK_FORMAT_R8G8B8A8_UNORM:VK_FORMAT_B8G8R8A8_UNORM, z_rgb);
case rsx::surface_color_format::x8r8g8b8_z8r8g8b8:
return std::make_pair(VK_FORMAT_R8G8B8A8_UNORM, z_rgb);
return std::make_pair(use_bgra8_fmt?VK_FORMAT_B8G8R8A8_UNORM:VK_FORMAT_R8G8B8A8_UNORM, z_rgb);
case rsx::surface_color_format::x8r8g8b8_o8r8g8b8:
return std::make_pair(VK_FORMAT_R8G8B8A8_UNORM, o_rgb);
return std::make_pair(use_bgra8_fmt?VK_FORMAT_B8G8R8A8_UNORM:VK_FORMAT_R8G8B8A8_UNORM, o_rgb);
case rsx::surface_color_format::w16z16y16x16:
return std::make_pair(VK_FORMAT_R16G16B16A16_SFLOAT, vk::default_component_map);
@@ -99,7 +101,7 @@ namespace vk
default:
rsx_log.error("Surface color buffer: Unsupported surface color format (0x%x)", static_cast<u32>(color_format));
return std::make_pair(VK_FORMAT_R8G8B8A8_UNORM, vk::default_component_map);
return std::make_pair(use_bgra8_fmt?VK_FORMAT_B8G8R8A8_UNORM:VK_FORMAT_R8G8B8A8_UNORM, vk::default_component_map);
}
}

View File

@@ -369,7 +369,7 @@ namespace vk
fs_src = fmt::replace_all(fs_src,
{
{ "%preprocessor", "// %preprocessor" },
{ "%preprocessor", g_cfg.video.bgra_format?"#define USE_BGRA":"// %preprocessor" },
{ "%push_block_offset", "layout(offset=68)" },
{ "%push_block", "push_constant" }
});
@@ -389,7 +389,7 @@ namespace vk
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_R8G8B8A8_UNORM;
const VkFormat format = (font) ? VK_FORMAT_R8_UNORM : (g_cfg.video.bgra_format.get()?VK_FORMAT_B8G8R8A8_UNORM:VK_FORMAT_R8G8B8A8_UNORM);
const u32 pitch = (font) ? w : w * 4;
const u32 data_size = pitch * h * layers;
const auto offset = upload_heap.alloc<512>(data_size);

View File

@@ -18,17 +18,16 @@ namespace
{
VkFormat RSX_display_format_to_vk_format(u8 format)
{
static const bool use_bgra_fmt=g_cfg.video.bgra_format.get();
switch (format)
{
default:
rsx_log.error("Unhandled video output format 0x%x", static_cast<s32>(format));
[[fallthrough]];
case CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8:
//return VK_FORMAT_B8G8R8A8_UNORM;
return VK_FORMAT_R8G8B8A8_UNORM;
return use_bgra_fmt?VK_FORMAT_B8G8R8A8_UNORM:VK_FORMAT_R8G8B8A8_UNORM;
case CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8B8G8R8:
//return VK_FORMAT_R8G8B8A8_UNORM;
return VK_FORMAT_B8G8R8A8_UNORM;
return use_bgra_fmt?VK_FORMAT_R8G8B8A8_UNORM:VK_FORMAT_B8G8R8A8_UNORM;
case CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_R16G16B16X16_FLOAT:
return VK_FORMAT_R16G16B16A16_SFLOAT;
}

View File

@@ -540,6 +540,8 @@ namespace vk
a_dst = a_src;
static const VkFormat dst_fmt=g_cfg.video.bgra_format.get()?VK_FORMAT_B8G8R8A8_UNORM:VK_FORMAT_R8G8B8A8_UNORM;
if (vk::is_renderpass_open(cmd))
{
vk::end_renderpass(cmd);
@@ -701,13 +703,13 @@ namespace vk
if (use_unsafe_transport)
{
auto typeless = vk::get_typeless_helper(VK_FORMAT_R8G8B8A8_UNORM, RSX_FORMAT_CLASS_COLOR, typeless_w, typeless_h);
auto typeless = vk::get_typeless_helper(dst_fmt, RSX_FORMAT_CLASS_COLOR, typeless_w, typeless_h);
change_image_layout(cmd, typeless, VK_IMAGE_LAYOUT_GENERAL);
stretch_image_typeless_unsafe(src, dst, typeless, src_rect, dst_rect, depth_stencil);
}
else
{
auto typeless_depth = vk::get_typeless_helper(VK_FORMAT_R8G8B8A8_UNORM, RSX_FORMAT_CLASS_COLOR, typeless_w, typeless_h);
auto typeless_depth = vk::get_typeless_helper(dst_fmt, RSX_FORMAT_CLASS_COLOR, typeless_w, typeless_h);
auto typeless_stencil = vk::get_typeless_helper(VK_FORMAT_R8_UNORM, RSX_FORMAT_CLASS_COLOR, typeless_w, typeless_h);
change_image_layout(cmd, typeless_depth, VK_IMAGE_LAYOUT_GENERAL);
change_image_layout(cmd, typeless_stencil, VK_IMAGE_LAYOUT_GENERAL);
@@ -726,7 +728,7 @@ namespace vk
// NOTE: While it may seem intuitive to use R32_SFLOAT as the carrier for the depth aspect, this does not work properly
// Floating point interpolation is non-linear from a bit-by-bit perspective and generates undesirable effects
auto typeless_depth = vk::get_typeless_helper(VK_FORMAT_R8G8B8A8_UNORM, RSX_FORMAT_CLASS_COLOR, typeless_w, typeless_h);
auto typeless_depth = vk::get_typeless_helper(dst_fmt, RSX_FORMAT_CLASS_COLOR, typeless_w, typeless_h);
auto typeless_stencil = vk::get_typeless_helper(VK_FORMAT_R8_UNORM, RSX_FORMAT_CLASS_COLOR, typeless_w, typeless_h);
change_image_layout(cmd, typeless_depth, VK_IMAGE_LAYOUT_GENERAL);
change_image_layout(cmd, typeless_stencil, VK_IMAGE_LAYOUT_GENERAL);

View File

@@ -1245,6 +1245,7 @@ namespace vk
bool texture_cache::render_target_format_is_compatible(vk::image* tex, u32 gcm_format)
{
static const bool use_bgra8_fmt=g_cfg.video.bgra_format.get();
auto vk_format = tex->info.format;
switch (gcm_format)
{
@@ -1253,14 +1254,14 @@ namespace vk
err_once("Format incompatibility detected, reporting failure to force data copy (VK_FORMAT=0x%X, GCM_FORMAT=0x%X)", static_cast<u32>(vk_format), gcm_format);
return false;
#ifndef __APPLE__
case CELL_GCM_TEXTURE_R5G6B5:
return (vk_format == VK_FORMAT_R5G6B5_UNORM_PACK16);
case CELL_GCM_TEXTURE_R5G6B5:
return (vk_format == VK_FORMAT_R5G6B5_UNORM_PACK16);
#else
// R5G6B5 is not supported by Metal
// R5G6B5 is not supported by Metal
case CELL_GCM_TEXTURE_R5G6B5:
return (vk_format == VK_FORMAT_B8G8R8A8_UNORM);
#endif
case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT:
case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT:
return (vk_format == VK_FORMAT_R16G16B16A16_SFLOAT);
case CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT:
return (vk_format == VK_FORMAT_R32G32B32A32_SFLOAT);
@@ -1268,7 +1269,7 @@ namespace vk
return (vk_format == VK_FORMAT_R32_SFLOAT);
case CELL_GCM_TEXTURE_A8R8G8B8:
case CELL_GCM_TEXTURE_D8R8G8B8:
return (vk_format == VK_FORMAT_R8G8B8A8_UNORM || vk_format == VK_FORMAT_D24_UNORM_S8_UINT || vk_format == VK_FORMAT_D32_SFLOAT_S8_UINT);
return (vk_format == (use_bgra8_fmt?VK_FORMAT_B8G8R8A8_UNORM:VK_FORMAT_R8G8B8A8_UNORM) || vk_format == VK_FORMAT_D24_UNORM_S8_UINT || vk_format == VK_FORMAT_D32_SFLOAT_S8_UINT);
case CELL_GCM_TEXTURE_B8:
return (vk_format == VK_FORMAT_R8_UNORM);
case CELL_GCM_TEXTURE_G8B8:

View File

@@ -318,12 +318,13 @@ namespace vk
present_possible = false;
}
const VkFormat surf_color_fmt=g_cfg.video.bgra_format?VK_FORMAT_B8G8R8A8_UNORM:VK_FORMAT_R8G8B8A8_UNORM;
if (!present_possible)
{
//Native(sw) swapchain
rsx_log.error("It is not possible for the currently selected GPU to present to the window (Likely caused by NVIDIA driver running the current display)");
rsx_log.warning("Falling back to software present support (native windowing API)");
auto swapchain = new swapchain_NATIVE(dev, -1, graphics_queue_idx, transfer_queue_idx);
auto swapchain = new swapchain_NATIVE(dev, -1, graphics_queue_idx, transfer_queue_idx,surf_color_fmt);
swapchain->create(window_handle);
return swapchain;
}
@@ -340,7 +341,7 @@ namespace vk
if (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED)
{
format = VK_FORMAT_R8G8B8A8_UNORM;
format = surf_color_fmt;
}
else
{
@@ -350,9 +351,9 @@ namespace vk
//Prefer BGRA8_UNORM to avoid sRGB compression (RADV)
for (auto& surface_format : surfFormats)
{
if (surface_format.format == VK_FORMAT_R8G8B8A8_UNORM)
if (surface_format.format == surf_color_fmt)
{
format = VK_FORMAT_R8G8B8A8_UNORM;
format = surf_color_fmt;
break;
}
}

View File

@@ -94,8 +94,11 @@ namespace vk
}
auto& tex = g_null_image_views[type];
static const VkFormat tex_fmt=g_cfg.video.bgra_format?VK_FORMAT_B8G8R8A8_UNORM:VK_FORMAT_R8G8B8A8_UNORM;
tex = std::make_unique<viewable_image>(*g_render_device, g_render_device->get_memory_mapping().device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
image_type, VK_FORMAT_R8G8B8A8_UNORM, size, size, 1, 1, num_layers, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
image_type, tex_fmt, size, size, 1, 1, num_layers, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, flags | VK_IMAGE_CREATE_ALLOW_NULL_RPCS3, VMM_ALLOCATION_POOL_SCRATCH);
if (!tex->value)

View File

@@ -48,7 +48,7 @@ namespace vk
virtual void init_swapchain_images(render_device& dev, u32 count) = 0;
public:
swapchain_base(physical_device& gpu, u32 present_queue, u32 graphics_queue, u32 transfer_queue, VkFormat format = VK_FORMAT_R8G8B8A8_UNORM);
swapchain_base(physical_device& gpu, u32 present_queue, u32 graphics_queue, u32 transfer_queue, VkFormat format);
virtual ~swapchain_base() = default;
@@ -98,7 +98,7 @@ namespace vk
std::vector<T> swapchain_images;
public:
abstract_swapchain_impl(physical_device& gpu, u32 present_queue, u32 graphics_queue, u32 transfer_queue, VkFormat format = VK_FORMAT_R8G8B8A8_UNORM)
abstract_swapchain_impl(physical_device& gpu, u32 present_queue, u32 graphics_queue, u32 transfer_queue, VkFormat format)
: swapchain_base(gpu, present_queue, graphics_queue, transfer_queue, format)
{}

View File

@@ -188,7 +188,13 @@ struct cfg_root : cfg::node
cfg::_enum<vertex_buffer_upload_mode> vertex_buffer_upload_mode{ this, "Vertex Buffer Upload Mode", vertex_buffer_upload_mode::_auto, false };
cfg::_enum<texture_upload_type> texture_upload_type{ this, "Texture Upload Mode", texture_upload_type::cpu, false };
cfg::_bool bgra_format{ this, "Use BGRA Format", true };
#if defined (__APPLE__)
cfg::_bool force_convert_texture{ this, "Force Convert Texture",true };
#else
cfg::_bool force_convert_texture{ this, "Force Convert Texture" };
#endif
struct node_vk : cfg::node
{
node_vk(cfg::node* _this) : cfg::node(_this, "Vulkan") {}

View File

@@ -2,13 +2,16 @@
package aenu.aps3e;
import java.io.*;
import java.util.Base64;
import java.util.HashMap;
import android.content.Context;
import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.view.*;
import android.util.*;
import org.json.JSONException;
import org.json.JSONObject;
public class Emulator
{
@@ -26,6 +29,38 @@ public class Emulator
String category;
String version;
boolean decrypt;
static JSONObject to_json(MetaInfo info) throws JSONException {
JSONObject jo=new JSONObject();
if(info.eboot_path!=null)
jo.put("eboot_path",info.eboot_path);
if(info.iso_uri!=null)
jo.put("iso_uri",info.iso_uri);
if(info.icon!=null)
jo.put("icon",Base64.getEncoder().encodeToString(info.icon));
jo.put("name",info.name);
jo.put("serial",info.serial);
jo.put("category",info.category);
jo.put("version",info.version);
jo.put("decrypt",info.decrypt);
return jo;
}
static MetaInfo from_json(JSONObject jo) throws JSONException{
MetaInfo meta=new MetaInfo();
if(jo.has("eboot_path"))
meta.eboot_path=jo.getString("eboot_path");
if(jo.has("iso_uri"))
meta.iso_uri=jo.getString("iso_uri");
if(jo.has("icon"))
meta.icon=Base64.getDecoder().decode(jo.getString("icon"));
meta.name=jo.getString("name");
meta.serial=jo.getString("serial");
meta.category=jo.getString("category");
meta.version=jo.getString("version");
meta.decrypt=jo.getBoolean("decrypt");
return meta;
}
}
public static class Config{

View File

@@ -41,7 +41,8 @@ import androidx.preference.Preference;
import androidx.preference.PreferenceDataStore;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceScreen;
import androidx.preference.SeekBarPreference;
//import androidx.preference.SeekBarPreference;
import aenu.preference.SeekbarPreference;
import java.io.File;
@@ -49,6 +50,7 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -271,6 +273,7 @@ public class EmulatorSettings extends AppCompatActivity {
"Video|DECR memory layout",
"Video|Allow Host GPU Labels",
"Video|Disable Asynchronous Memory Manager",
"Video|Use BGRA Format",
"Video|Vulkan|Force FIFO present mode",
"Video|Vulkan|Asynchronous Texture Streaming 2",
"Video|Vulkan|Use Custom Driver",
@@ -437,7 +440,7 @@ public class EmulatorSettings extends AppCompatActivity {
}
for (String key:INT_KEYS){
SeekBarPreference pref=findPreference(key);
SeekbarPreference pref=findPreference(key);
String val_str=config.load_config_entry(key);
if (val_str!=null) {
//FIXME
@@ -543,6 +546,12 @@ public class EmulatorSettings extends AppCompatActivity {
f.show(getParentFragmentManager(), "DIALOG_FRAGMENT_TAG");
return;
}
if (pref instanceof aenu.preference.SeekbarPreference) {
final DialogFragment f = aenu.preference.SeekbarPreference.SeekbarPreferenceFragmentCompat.newInstance(pref.getKey());
f.setTargetFragment(this, 0);
f.show(getParentFragmentManager(), "DIALOG_FRAGMENT_TAG");
return;
}
super.onDisplayPreferenceDialog(pref);
}
@@ -1030,13 +1039,14 @@ libs.put("libvpost2.sprx", 0);
libs.put("libwmadec.sprx", 0);
}
final String[] libs_name=libs.keySet().toArray(new String[0]);
String[] libs_name=libs.keySet().toArray(new String[0]);
final Map<String, Integer> modify=new HashMap<>();
Context context;
LibraryControlAdapter(Context ctx){
this.context=ctx;
Arrays.sort(libs_name);
}
int get_lib_type(int pos){

View File

@@ -40,6 +40,7 @@ public class KeyMapActivity extends Activity {
super.onCreate(bundle);
sp=getSharedPreferences();
lv=new ListView(this);
lv.setDividerHeight(32);
setContentView(lv);
update_config();
lv.setOnItemClickListener(click_l);
@@ -53,7 +54,7 @@ public class KeyMapActivity extends Activity {
void update_config(){
final SharedPreferences sPrefs = PreferenceManager.getDefaultSharedPreferences(KeyMapActivity.this);
SharedPreferences.Editor sPrefsEditor = sPrefs.edit();
for(int i=0;i<KeyMapConfig.KEY_NAMEIDS.length;i++){
String key_n=Integer.toString(KeyMapConfig.KEY_NAMEIDS[i]);
int default_v=KeyMapConfig.DEFAULT_KEYMAPPERS[i];
@@ -80,8 +81,8 @@ public class KeyMapActivity extends Activity {
public void onItemClick(final AdapterView<?> l, View v, final int position,long id)
{
AlertDialog.Builder builder = new AlertDialog.Builder(KeyMapActivity.this);
builder.setMessage("按任意键继续");
builder.setNegativeButton("清除", new DialogInterface.OnClickListener(){
builder.setMessage(R.string.press_a_key);
builder.setNegativeButton(R.string.clear, new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface p1, int p2)
{
@@ -130,6 +131,10 @@ public class KeyMapActivity extends Activity {
}
public String getKey(int pos){
return Integer.toString(keyNameIdList_[pos]);
}
public String getKeyName(int pos){
return context_.getString(keyNameIdList_[pos]);
}
@@ -157,9 +162,8 @@ public class KeyMapActivity extends Activity {
}
TextView text=(TextView)curView;
text.setMinHeight(64);
text.setText(getKey(pos)+": "+valueList_[pos]);
text.setText(getKeyName(pos)+": "+valueList_[pos]);
return curView;
}

View File

@@ -23,6 +23,7 @@ import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.preference.PreferenceManager;
import android.provider.DocumentsContract;
@@ -67,6 +68,10 @@ import android.view.*;
import androidx.documentfile.provider.DocumentFile;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class MainActivity extends Activity{
private static final int REQUEST_INSTALL_FIRMWARE=6001;
@@ -104,6 +109,11 @@ public class MainActivity extends Activity{
public static File get_config_file(){
return new File(Application.get_app_data_dir(),"config/config.yml");
}
public static File get_game_list_file(){
return new File(Application.get_app_data_dir(),"config/game_list.json");
}
public static File firmware_installed_file(){
return new File(Application.get_app_data_dir(),"config/dev_flash/.installed");
}
@@ -164,7 +174,7 @@ public class MainActivity extends Activity{
//if(is_request_perms_ok)
{
refresh_game_list();
show_game_list();
}
}
@@ -551,6 +561,8 @@ public class MainActivity extends Activity{
super.onDestroy();
}
void show_verify_dialog(int res_id, DialogInterface.OnClickListener listener){
new AlertDialog.Builder(this)
.setMessage(getString(res_id)+"?")
@@ -638,9 +650,7 @@ public class MainActivity extends Activity{
.set_done_task(new ProgressTask.UI_Task() {
@Override
public void run() {
((ListView)findViewById(R.id.game_list))
.setAdapter(adapter);
show_game_list();
progress_task=null;
}
}))
@@ -648,12 +658,34 @@ public class MainActivity extends Activity{
@Override
public void run(ProgressTask task) {
adapter=new GameMetaInfoAdapter(MainActivity.this);
File json_file=get_game_list_file();
if(json_file.exists())
json_file.delete();
GameMetaInfoAdapter.save_game_list_to_json_file(json_file,GameMetaInfoAdapter.refresh_game_list(MainActivity.this));
task.task_handler.sendEmptyMessage(ProgressTask.TASK_DONE);
}
});
}
private void show_game_list(){
if(!get_hdd0_game_dir().exists()){
get_hdd0_game_dir().mkdirs();
}
if(!get_disc_game_dir().exists()){
get_disc_game_dir().mkdirs();
}
try {
ArrayList<Emulator.MetaInfo> metas=GameMetaInfoAdapter.load_game_list_from_json_file(get_game_list_file());
adapter=new GameMetaInfoAdapter(this, metas);
((ListView)findViewById(R.id.game_list)).setAdapter(adapter);
} catch (Exception e) {
Log.w("show_game_list",e.getMessage());
refresh_game_list();
}
}
private static class GameMetaInfoAdapter extends BaseAdapter {
private static final FileFilter dir_filter_=new FileFilter(){
@@ -706,20 +738,59 @@ public class MainActivity extends Activity{
}
directory.delete();
}
ArrayList<Emulator.MetaInfo> metas;
private final MainActivity context_;
private GameMetaInfoAdapter(MainActivity context,ArrayList<Emulator.MetaInfo> metas){
context_=context;
this.metas=metas;
}
static ArrayList<Emulator.MetaInfo> load_game_list_from_json_file(File json) throws JSONException, IOException {
FileInputStream fis=new FileInputStream(json);
ByteArrayOutputStream baos=new ByteArrayOutputStream();
byte[] buffer=new byte[16384];
int n;
while ((n=fis.read(buffer))!=-1){
baos.write(buffer,0,n);
}
fis.close();
String json_str=baos.toString();
return load_game_list_from_json(json_str);
}
private ArrayList<File> game_dir_list;
private ArrayList<DocumentFile> iso_list;
private ArrayList<Emulator.MetaInfo> metas;
private MainActivity context_;
static ArrayList<Emulator.MetaInfo> load_game_list_from_json(String json_str) throws JSONException {
ArrayList<Emulator.MetaInfo> metas=new ArrayList<Emulator.MetaInfo>();
JSONArray game_list=new JSONArray(json_str);
for(int i=0;i<game_list.length();i++){
JSONObject game_info=game_list.getJSONObject(i);
Emulator.MetaInfo meta=Emulator.MetaInfo.from_json(game_info);
metas.add(meta);
}
return metas;
}
private GameMetaInfoAdapter(MainActivity context){
context_=context;
game_dir_list=get_game_dir_list();
iso_list=get_game_iso_list();
this.metas=gen_metas(game_dir_list,iso_list);
}
private ArrayList<File> get_game_dir_list(){
static void save_game_list_to_json_file(File json,ArrayList<Emulator.MetaInfo> metas){
try {
FileOutputStream fos=new FileOutputStream(json);
fos.write(save_game_list_to_json(metas).getBytes());
fos.close();
} catch (IOException | JSONException e) {
e.printStackTrace();
}
}
static String save_game_list_to_json(ArrayList<Emulator.MetaInfo> metas) throws JSONException {
JSONArray game_list=new JSONArray();
for(Emulator.MetaInfo meta:metas){
game_list.put(Emulator.MetaInfo.to_json(meta));
}
return game_list.toString();
}
static ArrayList<Emulator.MetaInfo> refresh_game_list(MainActivity context){
return gen_metas(context,get_game_dir_list(),get_game_iso_list(context));
}
private static ArrayList<File> get_game_dir_list(){
ArrayList<File> game_dir_list=new ArrayList<File>();
File[] game_dirs;
game_dirs=get_hdd0_game_dir().listFiles(dir_filter_);
@@ -735,7 +806,7 @@ public class MainActivity extends Activity{
return game_dir_list;
}
private ArrayList<DocumentFile> get_game_iso_list(){
private static ArrayList<DocumentFile> get_game_iso_list(MainActivity context_){
ArrayList<DocumentFile> iso_list=new ArrayList<DocumentFile>();
Uri uri=context_.load_pref_iso_dir();
if(uri==null)
@@ -753,7 +824,7 @@ public class MainActivity extends Activity{
return iso_list;
}
private ArrayList<Emulator.MetaInfo> gen_metas(ArrayList<File> dirs,ArrayList<DocumentFile> isos){
private static ArrayList<Emulator.MetaInfo> gen_metas(MainActivity context_,ArrayList<File> dirs,ArrayList<DocumentFile> isos){
ArrayList<Emulator.MetaInfo> metas=new ArrayList<Emulator.MetaInfo>();
for(File dir:dirs){
Emulator.MetaInfo meta=Emulator.get.meta_info_from_dir(dir.getAbsolutePath());

View File

@@ -129,6 +129,11 @@ public class UpdateLogActivity extends Activity{
+ " *增加选项(字体大小)\n"
//+ " *修复UB\n"
//+ " *协议追加\n"
+ "1.23(2025-06-19)\n"
+ " *优化了主菜单界面\n"
+ " *修复了按键映射无效的问题\n"
+ " *增加了选项使用BGRAg格式并默认启用\n"
+ " *设置优化(库控制排序,进度条可编辑)\n"
+ " \n";
@Override

View File

@@ -0,0 +1,432 @@
// SPDX-License-Identifier: Apache-2.0
// androidx.preference
package aenu.preference;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.widget.EditText;
import android.widget.SeekBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.preference.DialogPreference;
import androidx.preference.ListPreference;
import androidx.preference.ListPreferenceDialogFragmentCompat;
import androidx.preference.PreferenceDialogFragmentCompat;
import androidx.preference.PreferenceViewHolder;
import androidx.preference.SeekBarPreference;
import androidx.preference.R;
public class SeekbarPreference extends DialogPreference {
public static class SeekbarPreferenceFragmentCompat extends PreferenceDialogFragmentCompat {
private static final String SAVE_STATE_VALUE = "SeekbarPreferenceFragmentCompat.value";
private static final String SAVE_STATE_MIN = "SeekbarPreferenceFragmentCompat.min";
private static final String SAVE_STATE_MAX =
"SeekbarPreferenceFragmentCompat.max";
int m_value;
int m_min;
int m_max;
EditText mEditText;
@NonNull
public static SeekbarPreference.SeekbarPreferenceFragmentCompat newInstance(String key) {
final SeekbarPreference.SeekbarPreferenceFragmentCompat fragment =
new SeekbarPreference.SeekbarPreferenceFragmentCompat();
final Bundle b = new Bundle(1);
b.putString(ARG_KEY, key);
fragment.setArguments(b);
return fragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
final SeekbarPreference preference = getSeekbarPreference();
m_value = preference.getValue();
m_min = preference.getMin();
m_max = preference.getMax();
} else {
m_value = savedInstanceState.getInt(SAVE_STATE_VALUE);
m_min = savedInstanceState.getInt(SAVE_STATE_MIN);
m_max = savedInstanceState.getInt(SAVE_STATE_MAX);
}
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(SAVE_STATE_VALUE, m_value);
outState.putInt(SAVE_STATE_MIN, m_min);
outState.putInt(SAVE_STATE_MAX, m_max);
}
private SeekbarPreference getSeekbarPreference() {
return (SeekbarPreference) getPreference();
}
@Override
protected void onBindDialogView(@NonNull View view) {
super.onBindDialogView(view);
mEditText = (EditText) view.findViewById(android.R.id.edit);
if(mEditText!=null){
mEditText.setHint(Integer.toString(m_min)+" -> "+Integer.toString(m_max));
}
}
@Override
protected void onPrepareDialogBuilder(@NonNull AlertDialog.Builder builder) {
super.onPrepareDialogBuilder(builder);
// The typical interaction for list-based dialogs is to have click-on-an-item dismiss the
// dialog instead of the user having to press 'Ok'.
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if(mEditText!=null){
try{
int value = Integer.parseInt(mEditText.getText().toString());
if (value >= m_min && value <= m_max){
final SeekbarPreference preference = getSeekbarPreference();
if(preference.callChangeListener(value))
preference.setValue(value);
}
}catch(Exception e){
Log.e("SeekbarPreference",e.toString());
}
}
dialog.dismiss();
}
});
}
@Override
public void onDialogClosed(boolean positiveResult) {
if (positiveResult) {
try{
int value = Integer.parseInt(mEditText.getText().toString());
if (value >= m_min && value <= m_max){
final SeekbarPreference preference = getSeekbarPreference();
if(preference.callChangeListener(value))
preference.setValue(value);
}
}catch(Exception e){
Log.e("SeekbarPreference",e.toString());
}
}
}
}
int mSeekBarValue;
@SuppressWarnings("WeakerAccess") /* synthetic access */
int mMin;
private int mMax;
private int mSeekBarIncrement;
@SuppressWarnings("WeakerAccess") /* synthetic access */
boolean mTrackingTouch;
@SuppressWarnings("WeakerAccess") /* synthetic access */
SeekBar mSeekBar;
private TextView mSeekBarValueTextView;
// Whether the SeekBar should respond to the left/right keys
@SuppressWarnings("WeakerAccess") /* synthetic access */
boolean mAdjustable;
// Whether to show the SeekBar value TextView next to the bar
private boolean mShowSeekBarValue;
// Whether the SeekBarPreference should continuously save the Seekbar value while it is being
// dragged.
@SuppressWarnings("WeakerAccess") /* synthetic access */
boolean mUpdatesContinuously;
private final SeekBar.OnSeekBarChangeListener mSeekBarChangeListener = new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser && (mUpdatesContinuously || !mTrackingTouch)) {
syncValueInternal(seekBar);
} else {
// We always want to update the text while the seekbar is being dragged
updateLabelValue(progress + mMin);
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
mTrackingTouch = true;
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
mTrackingTouch = false;
if (seekBar.getProgress() + mMin != mSeekBarValue) {
syncValueInternal(seekBar);
}
}
};
/**
* Listener reacting to the user pressing DPAD left/right keys if {@code
* adjustable} attribute is set to true; it transfers the key presses to the {@link SeekBar}
* to be handled accordingly.
*/
private final View.OnKeyListener mSeekBarKeyListener = new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() != KeyEvent.ACTION_DOWN) {
return false;
}
if (!mAdjustable && (keyCode == KeyEvent.KEYCODE_DPAD_LEFT
|| keyCode == KeyEvent.KEYCODE_DPAD_RIGHT)) {
// Right or left keys are pressed when in non-adjustable mode; Skip the keys.
return false;
}
// We don't want to propagate the click keys down to the SeekBar view since it will
// create the ripple effect for the thumb.
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_ENTER) {
return false;
}
if (mSeekBar == null) {
return false;
}
return mSeekBar.onKeyDown(keyCode, event);
}
};
public SeekbarPreference(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
setDialogLayoutResource(aenu.aps3e.R.layout.edit_seek_bar);
TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.SeekBarPreference, defStyleAttr, defStyleRes);
// The ordering of these two statements are important. If we want to set max first, we need
// to perform the same steps by changing min/max to max/min as following:
// mMax = a.getInt(...) and setMin(...).
mMin = a.getInt(R.styleable.SeekBarPreference_min, 0);
setMax(a.getInt(R.styleable.SeekBarPreference_android_max, 100));
setSeekBarIncrement(a.getInt(R.styleable.SeekBarPreference_seekBarIncrement, 0));
mAdjustable = a.getBoolean(R.styleable.SeekBarPreference_adjustable, true);
mShowSeekBarValue = a.getBoolean(R.styleable.SeekBarPreference_showSeekBarValue, false);
mUpdatesContinuously = a.getBoolean(R.styleable.SeekBarPreference_updatesContinuously,
false);
a.recycle();
}
public SeekbarPreference(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public SeekbarPreference(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, R.attr.seekBarPreferenceStyle);
}
public SeekbarPreference(@NonNull Context context) {
this(context, null);
}
@Override
public void onBindViewHolder(@NonNull PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
holder.itemView.setOnKeyListener(mSeekBarKeyListener);
mSeekBar = (SeekBar) holder.findViewById(R.id.seekbar);
mSeekBarValueTextView = (TextView) holder.findViewById(R.id.seekbar_value);
if (mShowSeekBarValue) {
mSeekBarValueTextView.setVisibility(View.VISIBLE);
} else {
mSeekBarValueTextView.setVisibility(View.GONE);
mSeekBarValueTextView = null;
}
if (mSeekBar == null) {
//Log.e(TAG, "SeekBar view is null in onBindViewHolder.");
return;
}
mSeekBar.setOnSeekBarChangeListener(mSeekBarChangeListener);
mSeekBar.setMax(mMax - mMin);
// If the increment is not zero, use that. Otherwise, use the default mKeyProgressIncrement
// in AbsSeekBar when it's zero. This default increment value is set by AbsSeekBar
// after calling setMax. That's why it's important to call setKeyProgressIncrement after
// calling setMax() since setMax() can change the increment value.
if (mSeekBarIncrement != 0) {
mSeekBar.setKeyProgressIncrement(mSeekBarIncrement);
} else {
mSeekBarIncrement = mSeekBar.getKeyProgressIncrement();
}
mSeekBar.setProgress(mSeekBarValue - mMin);
updateLabelValue(mSeekBarValue);
mSeekBar.setEnabled(isEnabled());
}
@Override
protected void onSetInitialValue(Object defaultValue) {
if (defaultValue == null) {
defaultValue = 0;
}
setValue(getPersistedInt((Integer) defaultValue));
}
@Override
protected @Nullable Object onGetDefaultValue(@NonNull TypedArray a, int index) {
return a.getInt(index, 0);
}
public int getMin() {
return mMin;
}
/**
* Sets the lower bound on the {@link SeekBar}.
*
* @param min The lower bound to set
*/
public void setMin(int min) {
if (min > mMax) {
min = mMax;
}
if (min != mMin) {
mMin = min;
notifyChanged();
}
}
public int getValue() {
return mSeekBarValue;
}
/**
* Sets the current progress of the {@link SeekBar}.
*
* @param seekBarValue The current progress of the {@link SeekBar}
*/
public void setValue(int seekBarValue) {
setValueInternal(seekBarValue, true);
}
public final void setSeekBarIncrement(int seekBarIncrement) {
if (seekBarIncrement != mSeekBarIncrement) {
mSeekBarIncrement = Math.min(mMax - mMin, Math.abs(seekBarIncrement));
notifyChanged();
}
}
private void setValueInternal(int seekBarValue, boolean notifyChanged) {
if (seekBarValue < mMin) {
seekBarValue = mMin;
}
if (seekBarValue > mMax) {
seekBarValue = mMax;
}
if (seekBarValue != mSeekBarValue) {
mSeekBarValue = seekBarValue;
updateLabelValue(mSeekBarValue);
persistInt(seekBarValue);
if (notifyChanged) {
notifyChanged();
}
}
}
public int getMax() {
return mMax;
}
/**
* Sets the upper bound on the {@link SeekBar}.
*
* @param max The upper bound to set
*/
public final void setMax(int max) {
if (max < mMin) {
max = mMin;
}
if (max != mMax) {
mMax = max;
notifyChanged();
}
}
void syncValueInternal(@NonNull SeekBar seekBar) {
int seekBarValue = mMin + seekBar.getProgress();
if (seekBarValue != mSeekBarValue) {
if (callChangeListener(seekBarValue)) {
setValueInternal(seekBarValue, false);
} else {
seekBar.setProgress(mSeekBarValue - mMin);
updateLabelValue(mSeekBarValue);
}
}
}
/**
* Attempts to update the TextView label that displays the current value.
*
* @param value the value to display next to the {@link SeekBar}
*/
@SuppressWarnings("WeakerAccess") /* synthetic access */
void updateLabelValue(int value) {
if (mSeekBarValueTextView != null) {
mSeekBarValueTextView.setText(String.valueOf(value));
}
}
private static class SavedState extends BaseSavedState {
public static final Parcelable.Creator<SavedState> CREATOR =
new Parcelable.Creator<SavedState>() {
@Override
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
@Override
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
int mSeekBarValue;
int mMin;
int mMax;
SavedState(Parcel source) {
super(source);
// Restore the click counter
mSeekBarValue = source.readInt();
mMin = source.readInt();
mMax = source.readInt();
}
SavedState(Parcelable superState) {
super(superState);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
// Save the click counter
dest.writeInt(mSeekBarValue);
dest.writeInt(mMin);
dest.writeInt(mMax);
}
}
}

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@android:id/edit"
android:singleLine="true"
android:inputType="numberSigned" />
</LinearLayout>

View File

@@ -4,6 +4,9 @@
<string name="msg_processing">处理中...</string>
<string name="msg_failed">失败!</string>
<string name="clear">清除</string>
<string name="press_a_key">按任意键继续...</string>
<string name="game_list_loading">游戏列表载入中...</string>
<string name="undecrypted_game">暂不支持运行未解密的游戏</string>
<string name="delete_game_data">删除游戏数据</string>
@@ -328,6 +331,8 @@
<item>FidelityFX超级分辨率</item>
</string-array>
<string name="emulator_settings_video_use_bgra_format">使用BGRA格式</string>
<string name="emulator_settings_video_force_convert_texture">强制转换纹理</string>
<string name="emulator_settings_video_vulkan">Vulkan</string>
<string name="emulator_settings_video_vulkan_adapter">适配器</string>
<string name="emulator_settings_video_vulkan_force_fifo_present_mode">强制 FIFO 呈现模式</string>

View File

@@ -6,6 +6,8 @@
<string name="msg_processing">Processing...</string>
<string name="msg_failed">Failed!</string>
<string name="clear">Clear</string>
<string name="press_a_key">Press any key to continue...</string>
<string name="game_list_loading">The game list is loading...</string>
<string name="undecrypted_game">Running undecrypted games is not supported at this time</string>
<string name="delete_game_data">Delete Game Data</string>
@@ -323,6 +325,8 @@
<item>Bilinear</item>
<item>FidelityFX Super Resolution</item>
</string-array>
<string name="emulator_settings_video_use_bgra_format">Use BGRA Format</string>
<string name="emulator_settings_video_force_convert_texture">Force Convert Texture</string>
<string name="emulator_settings_video_vulkan">Vulkan</string>
<string name="emulator_settings_video_vulkan_adapter">Adapter</string>
<string name="emulator_settings_video_vulkan_force_fifo_present_mode">Force FIFO present mode</string>

View File

@@ -11,7 +11,7 @@
app:key="Core|PPU Decoder" />
<SeekBarPreference app:title="@string/emulator_settings_core_ppu_threads"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_core_ppu_threads"
app:min="1"
android:max="8"
app:showSeekBarValue="true"
@@ -34,7 +34,7 @@
app:key="Core|Use LLVM CPU" />
<SeekBarPreference app:title="@string/emulator_settings_core_max_llvm_compile_threads"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_core_max_llvm_compile_threads"
app:min="0"
android:max="12"
app:showSeekBarValue="true"
@@ -61,14 +61,14 @@
app:key="Core|SPU Decoder" />
<SeekBarPreference app:title="@string/emulator_settings_core_spu_reservation_busy_waiting_percentage"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_core_spu_reservation_busy_waiting_percentage"
app:min="0"
android:max="100"
app:showSeekBarValue="true"
app:key="Core|SPU Reservation Busy Waiting Percentage" />
<SeekBarPreference app:title="@string/emulator_settings_core_spu_getllar_busy_waiting_percentage"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_core_spu_getllar_busy_waiting_percentage"
app:min="0"
android:max="101"
app:showSeekBarValue="true"
@@ -87,14 +87,14 @@
app:key="Core|MFC Debug" />
<SeekBarPreference app:title="@string/emulator_settings_core_preferred_spu_threads"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_core_preferred_spu_threads"
app:min="0"
android:max="6"
app:showSeekBarValue="true"
app:key="Core|Preferred SPU Threads" />
<SeekBarPreference app:title="@string/emulator_settings_core_spu_delay_penalty"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_core_spu_delay_penalty"
app:min="0"
android:max="16"
app:showSeekBarValue="true"
@@ -105,7 +105,7 @@
app:key="Core|SPU loop detection" />
<SeekBarPreference app:title="@string/emulator_settings_core_max_spurs_threads"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_core_max_spurs_threads"
app:min="1"
android:max="6"
app:showSeekBarValue="true"
@@ -152,14 +152,14 @@
app:key="Core|SPU Profiler" />
<SeekBarPreference app:title="@string/emulator_settings_core_mfc_commands_shuffling_limit"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_core_mfc_commands_shuffling_limit"
app:min="0"
android:max="16"
app:showSeekBarValue="true"
app:key="Core|MFC Commands Shuffling Limit" />
<SeekBarPreference app:title="@string/emulator_settings_core_mfc_commands_timeout"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_core_mfc_commands_timeout"
app:min="0"
android:max="10000"
app:showSeekBarValue="true"
@@ -182,14 +182,14 @@
app:key="Core|XFloat Accuracy" />
<SeekBarPreference app:title="@string/emulator_settings_core_accurate_ppu_128byte_reservation_op_max_length"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_core_accurate_ppu_128byte_reservation_op_max_length"
app:min="-1"
android:max="14"
app:showSeekBarValue="true"
app:key="Core|Accurate PPU 128-byte Reservation Op Max Length" />
<SeekBarPreference app:title="@string/emulator_settings_core_stub_ppu_traps"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_core_stub_ppu_traps"
app:min="-64"
android:max="64"
app:showSeekBarValue="true"
@@ -244,42 +244,42 @@
app:key="Core|HLE lwmutex" />
<SeekBarPreference app:title="@string/emulator_settings_core_tsx_transaction_first_limit"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_core_tsx_transaction_first_limit"
app:min="0"
android:max="0x7fffffff"
app:showSeekBarValue="true"
app:key="Core|TSX Transaction First Limit" />
<SeekBarPreference app:title="@string/emulator_settings_core_tsx_transaction_second_limit"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_core_tsx_transaction_second_limit"
app:min="0"
android:max="0x7fffffff"
app:showSeekBarValue="true"
app:key="Core|TSX Transaction Second Limit" />
<SeekBarPreference app:title="@string/emulator_settings_core_clocks_scale"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_core_clocks_scale"
app:min="10"
android:max="3000"
app:showSeekBarValue="true"
app:key="Core|Clocks scale" />
<SeekBarPreference app:title="@string/emulator_settings_core_spu_wakeup_delay"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_core_spu_wakeup_delay"
app:min="0"
android:max="3000"
app:showSeekBarValue="true"
app:key="Core|SPU Wake-Up Delay" />
<SeekBarPreference app:title="@string/emulator_settings_core_spu_wakeup_delay_thread_mask"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_core_spu_wakeup_delay_thread_mask"
app:min="0"
android:max="63"
app:showSeekBarValue="true"
app:key="Core|SPU Wake-Up Delay Thread Mask" />
<SeekBarPreference app:title="@string/emulator_settings_core_max_cpu_preempt_count"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_core_max_cpu_preempt_count"
app:min="0"
android:max="400"
app:showSeekBarValue="true"
@@ -296,14 +296,14 @@
app:key="Core|Sleep Timers Accuracy" />
<SeekBarPreference app:title="@string/emulator_settings_core_usleep_time_addend"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_core_usleep_time_addend"
app:min="-1000"
android:max="1500"
app:showSeekBarValue="true"
app:key="Core|Usleep Time Addend" />
<SeekBarPreference app:title="@string/emulator_settings_core_performance_report_threshold"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_core_performance_report_threshold"
app:min="0"
android:max="0x7fffffff"
app:showSeekBarValue="true"
@@ -345,7 +345,7 @@
app:key="Video|Frame limit" />
<SeekBarPreference app:title="@string/emulator_settings_video_second_frame_limit"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_video_second_frame_limit"
app:min="0"
android:max="1000"
app:showSeekBarValue="true"
@@ -492,70 +492,70 @@
app:key="Video|Accurate ZCULL stats" />
<SeekBarPreference app:title="@string/emulator_settings_video_consecutive_frames_to_draw"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_video_consecutive_frames_to_draw"
app:min="1"
android:max="8"
app:showSeekBarValue="true"
app:key="Video|Consecutive Frames To Draw" />
<SeekBarPreference app:title="@string/emulator_settings_video_consecutive_frames_to_skip"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_video_consecutive_frames_to_skip"
app:min="1"
android:max="8"
app:showSeekBarValue="true"
app:key="Video|Consecutive Frames To Skip" />
<SeekBarPreference app:title="@string/emulator_settings_video_resolution_scale"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_video_resolution_scale"
app:min="25"
android:max="800"
app:showSeekBarValue="true"
app:key="Video|Resolution Scale" />
<SeekBarPreference app:title="@string/emulator_settings_video_anisotropic_filter_override"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_video_anisotropic_filter_override"
app:min="0"
android:max="16"
app:showSeekBarValue="true"
app:key="Video|Anisotropic Filter Override" />
<SeekBarPreference app:title="@string/emulator_settings_video_texture_lod_bias_addend"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_video_texture_lod_bias_addend"
app:min="-32"
android:max="32"
app:showSeekBarValue="true"
app:key="Video|Texture LOD Bias Addend" />
<SeekBarPreference app:title="@string/emulator_settings_video_minimum_scalable_dimension"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_video_minimum_scalable_dimension"
app:min="1"
android:max="1024"
app:showSeekBarValue="true"
app:key="Video|Minimum Scalable Dimension" />
<SeekBarPreference app:title="@string/emulator_settings_video_shader_compiler_threads"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_video_shader_compiler_threads"
app:min="0"
android:max="16"
app:showSeekBarValue="true"
app:key="Video|Shader Compiler Threads" />
<SeekBarPreference app:title="@string/emulator_settings_video_driver_recovery_timeout"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_video_driver_recovery_timeout"
app:min="0"
android:max="30000000"
app:showSeekBarValue="true"
app:key="Video|Driver Recovery Timeout" />
<SeekBarPreference app:title="@string/emulator_settings_video_driver_wakeup_delay"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_video_driver_wakeup_delay"
app:min="0"
android:max="16667"
app:showSeekBarValue="true"
app:key="Video|Driver Wake-Up Delay" />
<SeekBarPreference app:title="@string/emulator_settings_video_vblank_rate"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_video_vblank_rate"
app:min="1"
android:max="3000"
app:showSeekBarValue="true"
@@ -595,6 +595,14 @@
app:entryValues="@array/video_texture_upload_mode_values"
app:key="Video|Texture Upload Mode" />
<CheckBoxPreference app:title="@string/emulator_settings_video_use_bgra_format"
app:key="Video|Use BGRA Format" />
<CheckBoxPreference app:title="@string/emulator_settings_video_force_convert_texture"
app:key="Video|Force Convert Texture" />
<PreferenceScreen app:title="@string/emulator_settings_video_vulkan"
app:key="Video|Vulkan" >
@@ -616,7 +624,7 @@
app:key="Video|Vulkan|Asynchronous Texture Streaming 2" />
<SeekBarPreference app:title="@string/emulator_settings_video_vulkan_fidelityfx_cas_sharpening_intensity"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_video_vulkan_fidelityfx_cas_sharpening_intensity"
app:min="0"
android:max="100"
app:showSeekBarValue="true"
@@ -629,7 +637,7 @@
app:key="Video|Vulkan|Asynchronous Queue Scheduler" />
<SeekBarPreference app:title="@string/emulator_settings_video_vulkan_vram_allocation_limit"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_video_vulkan_vram_allocation_limit"
app:min="256"
android:max="16384"
app:showSeekBarValue="true"
@@ -663,14 +671,14 @@
app:key="Video|Performance Overlay|Enable Frametime Graph" />
<SeekBarPreference app:title="@string/emulator_settings_video_performance_overlay_framerate_datapoints"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_video_performance_overlay_framerate_datapoints"
app:min="2"
android:max="6000"
app:showSeekBarValue="true"
app:key="Video|Performance Overlay|Framerate datapoints" />
<SeekBarPreference app:title="@string/emulator_settings_video_performance_overlay_frametime_datapoints"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_video_performance_overlay_frametime_datapoints"
app:min="2"
android:max="6000"
app:showSeekBarValue="true"
@@ -695,14 +703,14 @@
app:key="Video|Performance Overlay|Frametime graph detail level" />
<SeekBarPreference app:title="@string/emulator_settings_video_performance_overlay_metrics_update_interval"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_video_performance_overlay_metrics_update_interval"
app:min="1"
android:max="1000"
app:showSeekBarValue="true"
app:key="Video|Performance Overlay|Metrics update interval (ms)" />
<SeekBarPreference app:title="@string/emulator_settings_video_performance_overlay_font_size"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_video_performance_overlay_font_size"
app:min="4"
android:max="36"
app:showSeekBarValue="true"
@@ -715,14 +723,18 @@
app:key="Video|Performance Overlay|Position" />
<SeekBarPreference app:title="@string/emulator_settings_video_performance_overlay_horizontal_margin"
<PreferenceScreen app:title="@string/emulator_settings_video_performance_overlay_font"
app:key="Video|Performance Overlay|Font" />
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_video_performance_overlay_horizontal_margin"
app:min="0"
android:max="1280"
app:showSeekBarValue="true"
app:key="Video|Performance Overlay|Horizontal Margin (px)" />
<SeekBarPreference app:title="@string/emulator_settings_video_performance_overlay_vertical_margin"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_video_performance_overlay_vertical_margin"
app:min="0"
android:max="720"
app:showSeekBarValue="true"
@@ -737,7 +749,7 @@
app:key="Video|Performance Overlay|Center Vertically" />
<SeekBarPreference app:title="@string/emulator_settings_video_performance_overlay_opacity"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_video_performance_overlay_opacity"
app:min="0"
android:max="100"
app:showSeekBarValue="true"
@@ -751,14 +763,14 @@
app:key="Video|Shader Loading Dialog|Allow custom background" />
<SeekBarPreference app:title="@string/emulator_settings_video_shader_loading_dialog_darkening_effect_strength"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_video_shader_loading_dialog_darkening_effect_strength"
app:min="0"
android:max="100"
app:showSeekBarValue="true"
app:key="Video|Shader Loading Dialog|Darkening effect strength" />
<SeekBarPreference app:title="@string/emulator_settings_video_shader_loading_dialog_blur_effect_strength"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_video_shader_loading_dialog_blur_effect_strength"
app:min="0"
android:max="100"
app:showSeekBarValue="true"
@@ -801,7 +813,7 @@
app:key="Audio|Audio Format" />
<SeekBarPreference app:title="@string/emulator_settings_audio_audio_formats"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_audio_audio_formats"
app:min="0"
android:max="255"
app:showSeekBarValue="true"
@@ -814,7 +826,7 @@
app:key="Audio|Audio Channel Layout" />
<SeekBarPreference app:title="@string/emulator_settings_audio_master_volume"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_audio_master_volume"
app:min="0"
android:max="200"
app:showSeekBarValue="true"
@@ -825,7 +837,7 @@
app:key="Audio|Enable Buffering" />
<SeekBarPreference app:title="@string/emulator_settings_audio_desired_audio_buffer_duration"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_audio_desired_audio_buffer_duration"
app:min="4"
android:max="250"
app:showSeekBarValue="true"
@@ -840,7 +852,7 @@
app:key="Audio|Disable Sampling Skip" />
<SeekBarPreference app:title="@string/emulator_settings_audio_time_stretching_threshold"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_audio_time_stretching_threshold"
app:min="0"
android:max="100"
app:showSeekBarValue="true"
@@ -926,7 +938,7 @@
app:key="Input/Output|Keep pads connected" />
<SeekBarPreference app:title="@string/emulator_settings_input_output_pad_handler_sleep"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_input_output_pad_handler_sleep"
app:min="0"
android:max="100000"
app:showSeekBarValue="true"
@@ -1072,7 +1084,7 @@
app:key="Miscellaneous|Custom Font File Path" />
<SeekBarPreference app:title="@string/emulator_settings_miscellaneous_font_size"
<aenu.preference.SeekbarPreference app:title="@string/emulator_settings_miscellaneous_font_size"
app:min="12"
android:max="26"
app:showSeekBarValue="true"