mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Optimize Android build configurations and improve texture handling with NEON support
This commit is contained in:
@@ -42,12 +42,13 @@ android {
|
||||
arguments += listOf(
|
||||
"-DXEMU_ANDROID_BUILD_ID=3",
|
||||
"-DXEMU_ENABLE_XISO_CONVERTER=ON",
|
||||
"-DCMAKE_C_FLAGS_DEBUG=-O2 -g0",
|
||||
"-DCMAKE_CXX_FLAGS_DEBUG=-O2 -g0",
|
||||
"-DCMAKE_C_FLAGS_RELWITHDEBINFO=-O3 -g0",
|
||||
"-DCMAKE_CXX_FLAGS_RELWITHDEBINFO=-O3 -g0",
|
||||
"-DCMAKE_C_FLAGS_RELEASE=-O3 -g0",
|
||||
"-DCMAKE_CXX_FLAGS_RELEASE=-O3 -g0"
|
||||
"-DCMAKE_C_FLAGS_DEBUG=-O2 -g0 -march=armv8-a+simd -fvisibility=hidden -ffunction-sections -fdata-sections",
|
||||
"-DCMAKE_CXX_FLAGS_DEBUG=-O2 -g0 -march=armv8-a+simd -fvisibility=hidden -ffunction-sections -fdata-sections",
|
||||
"-DCMAKE_C_FLAGS_RELWITHDEBINFO=-O3 -g0 -march=armv8-a+simd -fvisibility=hidden -ffunction-sections -fdata-sections",
|
||||
"-DCMAKE_CXX_FLAGS_RELWITHDEBINFO=-O3 -g0 -march=armv8-a+simd -fvisibility=hidden -ffunction-sections -fdata-sections",
|
||||
"-DCMAKE_C_FLAGS_RELEASE=-O3 -g0 -march=armv8-a+simd -fvisibility=hidden -ffunction-sections -fdata-sections",
|
||||
"-DCMAKE_CXX_FLAGS_RELEASE=-O3 -g0 -march=armv8-a+simd -fvisibility=hidden -ffunction-sections -fdata-sections",
|
||||
"-DCMAKE_SHARED_LINKER_FLAGS=-Wl,--gc-sections"
|
||||
)
|
||||
cppFlags += listOf("-std=c++17", "-fexceptions", "-frtti")
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -144,18 +145,29 @@ static void AppendNativeDebugLog(const char* level, const char* message) {
|
||||
|
||||
SDL_LockMutex(g_native_debug_log_mutex);
|
||||
|
||||
/* Use POSIX write() with O_APPEND instead of std::ofstream to avoid
|
||||
* repeated file open/close overhead and C++ stream construction. */
|
||||
struct stat st {};
|
||||
const bool should_truncate =
|
||||
stat(g_native_debug_log_path.c_str(), &st) == 0 &&
|
||||
st.st_size > kMaxDebugLogBytes;
|
||||
if (stat(g_native_debug_log_path.c_str(), &st) == 0 &&
|
||||
st.st_size > kMaxDebugLogBytes) {
|
||||
/* Truncate oversized log file */
|
||||
int tfd = open(g_native_debug_log_path.c_str(), O_WRONLY | O_TRUNC);
|
||||
if (tfd >= 0) close(tfd);
|
||||
}
|
||||
|
||||
std::ofstream out(
|
||||
g_native_debug_log_path,
|
||||
should_truncate ? (std::ios::out | std::ios::trunc)
|
||||
: (std::ios::out | std::ios::app));
|
||||
if (out.is_open()) {
|
||||
out << CurrentNativeLogTimestamp() << ' ' << level << '/' << kLogTag
|
||||
<< ": " << message << '\n';
|
||||
int fd = open(g_native_debug_log_path.c_str(),
|
||||
O_WRONLY | O_CREAT | O_APPEND, 0644);
|
||||
if (fd >= 0) {
|
||||
char buf[2048];
|
||||
std::string ts = CurrentNativeLogTimestamp();
|
||||
int len = snprintf(buf, sizeof(buf), "%s %s/%s: %s\n",
|
||||
ts.c_str(), level, kLogTag, message);
|
||||
if (len > 0) {
|
||||
size_t bytes_to_write =
|
||||
(size_t)((len < (int)sizeof(buf) - 1) ? len : (int)sizeof(buf) - 1);
|
||||
(void)write(fd, buf, bytes_to_write);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
SDL_UnlockMutex(g_native_debug_log_mutex);
|
||||
|
||||
@@ -59,6 +59,7 @@ typedef struct XemuFatxCache {
|
||||
uint32_t entry_size;
|
||||
bool dirty;
|
||||
void *data;
|
||||
size_t data_capacity;
|
||||
} XemuFatxCache;
|
||||
|
||||
typedef struct XemuFatxFs {
|
||||
@@ -375,11 +376,15 @@ static bool xemu_fatx_populate_fat_cache(XemuFatxFs *fs, uint32_t index)
|
||||
cache->dirty = false;
|
||||
}
|
||||
|
||||
g_free(cache->data);
|
||||
cache->position = index;
|
||||
cache->entries = MIN(XEMU_FATX_FAT_CACHE_NUM_ENTRIES, fs->fat_entry_count - index);
|
||||
cache->entry_size = fs->fat_type == XEMU_FATX_FAT_TYPE_16 ? 2 : 4;
|
||||
cache->data = g_malloc(cache->entries * cache->entry_size);
|
||||
size_t needed = (size_t)cache->entries * cache->entry_size;
|
||||
if (needed > cache->data_capacity) {
|
||||
g_free(cache->data);
|
||||
cache->data = g_malloc(needed);
|
||||
cache->data_capacity = needed;
|
||||
}
|
||||
|
||||
xemu_fatx_dev_seek(fs, fs->fat_offset +
|
||||
(uint64_t)cache->position * cache->entry_size);
|
||||
|
||||
@@ -203,6 +203,8 @@ typedef struct PGRAPHGLState {
|
||||
size_t android_conv_buf_size;
|
||||
uint8_t *android_s2t_conv_buf; /* render-to-texture conversion */
|
||||
size_t android_s2t_conv_buf_size;
|
||||
uint8_t *android_tex_conv_buf; /* texture upload conversion */
|
||||
size_t android_tex_conv_buf_size;
|
||||
#endif
|
||||
|
||||
TextureBinding *texture_binding[NV2A_MAX_TEXTURES];
|
||||
|
||||
@@ -29,6 +29,9 @@
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <android/log.h>
|
||||
#ifdef __aarch64__
|
||||
#include <arm_neon.h>
|
||||
#endif
|
||||
|
||||
static void android_log_gl_errors(const char *ctx)
|
||||
{
|
||||
@@ -231,48 +234,116 @@ static void android_texture_convert_to_rgba8(const TextureShape s,
|
||||
}
|
||||
case NV097_SET_TEXTURE_FORMAT_COLOR_SZ_A8R8G8B8:
|
||||
case NV097_SET_TEXTURE_FORMAT_COLOR_SZ_I8_A8R8G8B8:
|
||||
case NV097_SET_TEXTURE_FORMAT_COLOR_LU_IMAGE_A8R8G8B8: {
|
||||
const uint8_t *pixel = src_row + x * 4;
|
||||
out[0] = pixel[2];
|
||||
out[1] = pixel[1];
|
||||
out[2] = pixel[0];
|
||||
out[3] = pixel[3];
|
||||
break;
|
||||
}
|
||||
case NV097_SET_TEXTURE_FORMAT_COLOR_LU_IMAGE_A8R8G8B8:
|
||||
case NV097_SET_TEXTURE_FORMAT_COLOR_SZ_X8R8G8B8:
|
||||
case NV097_SET_TEXTURE_FORMAT_COLOR_LU_IMAGE_X8R8G8B8: {
|
||||
bool preserve_alpha =
|
||||
(s.color_format != NV097_SET_TEXTURE_FORMAT_COLOR_SZ_X8R8G8B8 &&
|
||||
s.color_format != NV097_SET_TEXTURE_FORMAT_COLOR_LU_IMAGE_X8R8G8B8);
|
||||
#ifdef __aarch64__
|
||||
/* NEON BGRA→RGBA shuffle: process 4 pixels (16 bytes) at a time */
|
||||
static const uint8_t perm_arr[16] =
|
||||
{2,1,0,3, 6,5,4,7, 10,9,8,11, 14,13,12,15};
|
||||
uint8x16_t vperm = vld1q_u8(perm_arr);
|
||||
static const uint8_t alpha_mask_arr[16] =
|
||||
{0,0,0,0xFF, 0,0,0,0xFF, 0,0,0,0xFF, 0,0,0,0xFF};
|
||||
uint8x16_t valpha_mask = preserve_alpha
|
||||
? vdupq_n_u8(0)
|
||||
: vld1q_u8(alpha_mask_arr);
|
||||
unsigned int remaining = width - x;
|
||||
const uint8_t *sp = src_row + x * 4;
|
||||
uint8_t *dp = out;
|
||||
while (remaining >= 4) {
|
||||
uint8x16_t v = vqtbl1q_u8(vld1q_u8(sp), vperm);
|
||||
vst1q_u8(dp, vorrq_u8(v, valpha_mask));
|
||||
sp += 16; dp += 16; remaining -= 4;
|
||||
}
|
||||
while (remaining-- > 0) {
|
||||
dp[0] = sp[2]; dp[1] = sp[1];
|
||||
dp[2] = sp[0]; dp[3] = preserve_alpha ? sp[3] : 0xFF;
|
||||
sp += 4; dp += 4;
|
||||
}
|
||||
x = width; /* skip remaining scalar iterations */
|
||||
#else
|
||||
const uint8_t *pixel = src_row + x * 4;
|
||||
out[0] = pixel[2];
|
||||
out[1] = pixel[1];
|
||||
out[2] = pixel[0];
|
||||
out[3] = 0xFF;
|
||||
out[3] = preserve_alpha ? pixel[3] : 0xFF;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case NV097_SET_TEXTURE_FORMAT_COLOR_SZ_B8G8R8A8:
|
||||
case NV097_SET_TEXTURE_FORMAT_COLOR_LU_IMAGE_B8G8R8A8: {
|
||||
#ifdef __aarch64__
|
||||
/* NEON B8G8R8A8→RGBA8: rotate bytes within each pixel */
|
||||
static const uint8_t perm_arr[16] =
|
||||
{1,2,3,0, 5,6,7,4, 9,10,11,8, 13,14,15,12};
|
||||
uint8x16_t vperm = vld1q_u8(perm_arr);
|
||||
unsigned int remaining = width - x;
|
||||
const uint8_t *sp = src_row + x * 4;
|
||||
uint8_t *dp = out;
|
||||
while (remaining >= 4) {
|
||||
vst1q_u8(dp, vqtbl1q_u8(vld1q_u8(sp), vperm));
|
||||
sp += 16; dp += 16; remaining -= 4;
|
||||
}
|
||||
while (remaining-- > 0) {
|
||||
dp[0] = sp[1]; dp[1] = sp[2];
|
||||
dp[2] = sp[3]; dp[3] = sp[0];
|
||||
sp += 4; dp += 4;
|
||||
}
|
||||
x = width;
|
||||
#else
|
||||
const uint8_t *pixel = src_row + x * 4;
|
||||
out[0] = pixel[1];
|
||||
out[1] = pixel[2];
|
||||
out[2] = pixel[3];
|
||||
out[3] = pixel[0];
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case NV097_SET_TEXTURE_FORMAT_COLOR_SZ_A8B8G8R8:
|
||||
case NV097_SET_TEXTURE_FORMAT_COLOR_LU_IMAGE_A8B8G8R8: {
|
||||
#ifdef __aarch64__
|
||||
/* A8B8G8R8 is already RGBA8 — bulk memcpy */
|
||||
memcpy(out, src_row + x * 4, (width - x) * 4);
|
||||
x = width;
|
||||
#else
|
||||
const uint8_t *pixel = src_row + x * 4;
|
||||
out[0] = pixel[0];
|
||||
out[1] = pixel[1];
|
||||
out[2] = pixel[2];
|
||||
out[3] = pixel[3];
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case NV097_SET_TEXTURE_FORMAT_COLOR_SZ_R8G8B8A8:
|
||||
case NV097_SET_TEXTURE_FORMAT_COLOR_LU_IMAGE_R8G8B8A8: {
|
||||
#ifdef __aarch64__
|
||||
/* NEON R8G8B8A8→RGBA8: full byte reverse per pixel */
|
||||
static const uint8_t perm_arr[16] =
|
||||
{3,2,1,0, 7,6,5,4, 11,10,9,8, 15,14,13,12};
|
||||
uint8x16_t vperm = vld1q_u8(perm_arr);
|
||||
unsigned int remaining = width - x;
|
||||
const uint8_t *sp = src_row + x * 4;
|
||||
uint8_t *dp = out;
|
||||
while (remaining >= 4) {
|
||||
vst1q_u8(dp, vqtbl1q_u8(vld1q_u8(sp), vperm));
|
||||
sp += 16; dp += 16; remaining -= 4;
|
||||
}
|
||||
while (remaining-- > 0) {
|
||||
dp[0] = sp[3]; dp[1] = sp[2];
|
||||
dp[2] = sp[1]; dp[3] = sp[0];
|
||||
sp += 4; dp += 4;
|
||||
}
|
||||
x = width;
|
||||
#else
|
||||
const uint8_t *pixel = src_row + x * 4;
|
||||
out[0] = pixel[3];
|
||||
out[1] = pixel[2];
|
||||
out[2] = pixel[1];
|
||||
out[3] = pixel[0];
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case NV097_SET_TEXTURE_FORMAT_COLOR_LU_IMAGE_G8B8:
|
||||
@@ -300,7 +371,8 @@ static void android_texture_convert_to_rgba8(const TextureShape s,
|
||||
}
|
||||
}
|
||||
|
||||
static void android_prepare_tex_upload(const TextureShape s,
|
||||
static void android_prepare_tex_upload(PGRAPHGLState *r,
|
||||
const TextureShape s,
|
||||
const uint8_t *src,
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
@@ -310,11 +382,9 @@ static void android_prepare_tex_upload(const TextureShape s,
|
||||
GLint *ifmt,
|
||||
GLenum *fmt,
|
||||
GLenum *type,
|
||||
const uint8_t **upload_data,
|
||||
uint8_t **upload_tmp)
|
||||
const uint8_t **upload_data)
|
||||
{
|
||||
*upload_data = src;
|
||||
*upload_tmp = NULL;
|
||||
*ifmt = kelvin_color_format_gl_map[s.color_format].gl_internal_format;
|
||||
*fmt = kelvin_color_format_gl_map[s.color_format].gl_format;
|
||||
*type = kelvin_color_format_gl_map[s.color_format].gl_type;
|
||||
@@ -323,10 +393,16 @@ static void android_prepare_tex_upload(const TextureShape s,
|
||||
return;
|
||||
}
|
||||
|
||||
*upload_tmp = g_malloc(width * height * depth * 4);
|
||||
size_t needed = (size_t)width * height * depth * 4;
|
||||
if (needed > r->android_tex_conv_buf_size) {
|
||||
g_free(r->android_tex_conv_buf);
|
||||
r->android_tex_conv_buf = g_malloc(needed);
|
||||
r->android_tex_conv_buf_size = needed;
|
||||
}
|
||||
android_texture_convert_to_rgba8(s, src, width, height, depth,
|
||||
row_pitch, slice_pitch, *upload_tmp);
|
||||
*upload_data = *upload_tmp;
|
||||
row_pitch, slice_pitch,
|
||||
r->android_tex_conv_buf);
|
||||
*upload_data = r->android_tex_conv_buf;
|
||||
*ifmt = GL_RGBA8;
|
||||
*fmt = GL_RGBA;
|
||||
*type = GL_UNSIGNED_BYTE;
|
||||
@@ -383,7 +459,7 @@ static void pgraph_gl_log_invalid_texture_range(NV2AState *d,
|
||||
#endif
|
||||
}
|
||||
|
||||
static TextureBinding* generate_texture(const TextureShape s, const uint8_t *texture_data, const uint8_t *palette_data);
|
||||
static TextureBinding* generate_texture(PGRAPHGLState *r, const TextureShape s, const uint8_t *texture_data, const uint8_t *palette_data);
|
||||
static void texture_binding_destroy(gpointer data);
|
||||
|
||||
struct pgraph_texture_possibly_dirty_struct {
|
||||
@@ -810,7 +886,7 @@ void pgraph_gl_bind_textures(NV2AState *d)
|
||||
|
||||
if (key_out->binding == NULL) {
|
||||
// Must create the texture
|
||||
key_out->binding = generate_texture(state, texture_data, palette_data);
|
||||
key_out->binding = generate_texture(r, state, texture_data, palette_data);
|
||||
key_out->binding->data_hash = tex_data_hash;
|
||||
key_out->binding->scale = 1;
|
||||
#ifdef __ANDROID__
|
||||
@@ -894,11 +970,13 @@ gl_internal_format_to_s3tc_enum(GLint gl_internal_format)
|
||||
}
|
||||
}
|
||||
|
||||
static void upload_gl_texture(GLenum gl_target,
|
||||
static void upload_gl_texture(PGRAPHGLState *r,
|
||||
GLenum gl_target,
|
||||
const TextureShape s,
|
||||
const uint8_t *texture_data,
|
||||
const uint8_t *palette_data)
|
||||
{
|
||||
(void)r; /* used only in Android-specific paths */
|
||||
ColorFormatInfo f = kelvin_color_format_gl_map[s.color_format];
|
||||
nv2a_profile_inc_counter(NV2A_PROF_TEX_UPLOAD);
|
||||
#ifdef __ANDROID__
|
||||
@@ -935,7 +1013,6 @@ static void upload_gl_texture(GLenum gl_target,
|
||||
{
|
||||
const uint8_t *pixel_data = converted ? converted : texture_data;
|
||||
const uint8_t *upload_data = pixel_data;
|
||||
uint8_t *upload_tmp = NULL;
|
||||
unsigned int source_bpp =
|
||||
#ifdef __ANDROID__
|
||||
android_texture_source_bpp(s, f.bytes_per_pixel,
|
||||
@@ -949,11 +1026,11 @@ static void upload_gl_texture(GLenum gl_target,
|
||||
GLint tex_ifmt = f.gl_internal_format;
|
||||
GLenum tex_type = f.gl_type;
|
||||
#ifdef __ANDROID__
|
||||
android_prepare_tex_upload(s, pixel_data, adjusted_width,
|
||||
android_prepare_tex_upload(r, s, pixel_data, adjusted_width,
|
||||
adjusted_height, 1, row_pitch,
|
||||
row_pitch * adjusted_height,
|
||||
&tex_ifmt, &tex_fmt, &tex_type,
|
||||
&upload_data, &upload_tmp);
|
||||
&upload_data);
|
||||
#endif
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH,
|
||||
upload_data == texture_data ?
|
||||
@@ -963,9 +1040,6 @@ static void upload_gl_texture(GLenum gl_target,
|
||||
tex_fmt, tex_type,
|
||||
upload_data);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
#ifdef __ANDROID__
|
||||
g_free(upload_tmp);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (converted) {
|
||||
@@ -1000,8 +1074,10 @@ static void upload_gl_texture(GLenum gl_target,
|
||||
texture_data, width, height);
|
||||
unsigned int tex_width = width;
|
||||
unsigned int tex_height = height;
|
||||
bool need_cubemap_border_strip =
|
||||
s.cubemap && adjusted_width != s.width;
|
||||
|
||||
if (s.cubemap && adjusted_width != s.width) {
|
||||
if (need_cubemap_border_strip) {
|
||||
// FIXME: Consider preserving the border.
|
||||
// There does not seem to be a way to reference the border
|
||||
// texels in a cubemap, so they are discarded.
|
||||
@@ -1019,7 +1095,7 @@ static void upload_gl_texture(GLenum gl_target,
|
||||
glTexImage2D(gl_target, level, GL_RGBA8, tex_width, tex_height,
|
||||
0, GL_RGBA, GL_UNSIGNED_BYTE, converted);
|
||||
g_free(converted);
|
||||
if (s.cubemap && adjusted_width != s.width) {
|
||||
if (need_cubemap_border_strip) {
|
||||
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
|
||||
glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
|
||||
if (physical_width == width) {
|
||||
@@ -1059,16 +1135,15 @@ static void upload_gl_texture(GLenum gl_target,
|
||||
|
||||
{
|
||||
const uint8_t *upload_data = pixel_data;
|
||||
uint8_t *upload_tmp = NULL;
|
||||
GLenum tex_fmt = f.gl_format;
|
||||
GLint tex_ifmt = f.gl_internal_format;
|
||||
GLenum tex_type = f.gl_type;
|
||||
#ifdef __ANDROID__
|
||||
android_prepare_tex_upload(s, pixel_data, tex_width,
|
||||
android_prepare_tex_upload(r, s, pixel_data, tex_width,
|
||||
tex_height, 1, row_pitch,
|
||||
row_pitch * tex_height,
|
||||
&tex_ifmt, &tex_fmt, &tex_type,
|
||||
&upload_data, &upload_tmp);
|
||||
&upload_data);
|
||||
#endif
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH,
|
||||
upload_data == pixel_data &&
|
||||
@@ -1078,9 +1153,6 @@ static void upload_gl_texture(GLenum gl_target,
|
||||
tex_height, 0, tex_fmt, tex_type,
|
||||
upload_data);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
#ifdef __ANDROID__
|
||||
g_free(upload_tmp);
|
||||
#endif
|
||||
}
|
||||
if (converted) {
|
||||
g_free(converted);
|
||||
@@ -1153,7 +1225,6 @@ static void upload_gl_texture(GLenum gl_target,
|
||||
{
|
||||
const uint8_t *pixel_data = converted ? converted : unswizzled;
|
||||
const uint8_t *upload_data = pixel_data;
|
||||
uint8_t *upload_tmp = NULL;
|
||||
unsigned int source_bpp =
|
||||
#ifdef __ANDROID__
|
||||
android_texture_source_bpp(s, f.bytes_per_pixel,
|
||||
@@ -1167,19 +1238,16 @@ static void upload_gl_texture(GLenum gl_target,
|
||||
GLint tex_ifmt = f.gl_internal_format;
|
||||
GLenum tex_type = f.gl_type;
|
||||
#ifdef __ANDROID__
|
||||
android_prepare_tex_upload(s, pixel_data, width, height,
|
||||
android_prepare_tex_upload(r, s, pixel_data, width, height,
|
||||
depth, upload_row_pitch,
|
||||
upload_slice_pitch, &tex_ifmt,
|
||||
&tex_fmt, &tex_type,
|
||||
&upload_data, &upload_tmp);
|
||||
&upload_data);
|
||||
#endif
|
||||
glTexImage3D(gl_target, level, tex_ifmt,
|
||||
width, height, depth, 0,
|
||||
tex_fmt, tex_type,
|
||||
upload_data);
|
||||
#ifdef __ANDROID__
|
||||
g_free(upload_tmp);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (converted) {
|
||||
@@ -1205,7 +1273,8 @@ static void upload_gl_texture(GLenum gl_target,
|
||||
#endif
|
||||
}
|
||||
|
||||
static TextureBinding* generate_texture(const TextureShape s,
|
||||
static TextureBinding* generate_texture(PGRAPHGLState *r,
|
||||
const TextureShape s,
|
||||
const uint8_t *texture_data,
|
||||
const uint8_t *palette_data)
|
||||
{
|
||||
@@ -1282,20 +1351,20 @@ static TextureBinding* generate_texture(const TextureShape s,
|
||||
|
||||
length = (length + NV2A_CUBEMAP_FACE_ALIGNMENT - 1) & ~(NV2A_CUBEMAP_FACE_ALIGNMENT - 1);
|
||||
|
||||
upload_gl_texture(GL_TEXTURE_CUBE_MAP_POSITIVE_X,
|
||||
upload_gl_texture(r, GL_TEXTURE_CUBE_MAP_POSITIVE_X,
|
||||
s, texture_data + 0 * length, palette_data);
|
||||
upload_gl_texture(GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
|
||||
upload_gl_texture(r, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
|
||||
s, texture_data + 1 * length, palette_data);
|
||||
upload_gl_texture(GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
|
||||
upload_gl_texture(r, GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
|
||||
s, texture_data + 2 * length, palette_data);
|
||||
upload_gl_texture(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
|
||||
upload_gl_texture(r, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
|
||||
s, texture_data + 3 * length, palette_data);
|
||||
upload_gl_texture(GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
|
||||
upload_gl_texture(r, GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
|
||||
s, texture_data + 4 * length, palette_data);
|
||||
upload_gl_texture(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
|
||||
upload_gl_texture(r, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
|
||||
s, texture_data + 5 * length, palette_data);
|
||||
} else {
|
||||
upload_gl_texture(gl_target, s, texture_data, palette_data);
|
||||
upload_gl_texture(r, gl_target, s, texture_data, palette_data);
|
||||
}
|
||||
|
||||
/* Linear textures don't support mipmapping */
|
||||
@@ -1415,4 +1484,9 @@ void pgraph_gl_finalize_textures(PGRAPHState *pg)
|
||||
free(r->texture_cache_entries);
|
||||
|
||||
r->texture_cache_entries = NULL;
|
||||
#ifdef __ANDROID__
|
||||
g_free(r->android_tex_conv_buf);
|
||||
r->android_tex_conv_buf = NULL;
|
||||
r->android_tex_conv_buf_size = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -23,6 +23,11 @@ NV2AStats g_nv2a_stats;
|
||||
|
||||
void nv2a_profile_increment(void)
|
||||
{
|
||||
#ifdef __ANDROID__
|
||||
/* Skip profiling on Android — stats are never displayed and the
|
||||
* qemu_clock_get_us() syscalls add unnecessary overhead per frame. */
|
||||
return;
|
||||
#else
|
||||
int64_t now = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
|
||||
const int64_t fps_update_interval = 250000;
|
||||
g_nv2a_stats.last_flip_time = now;
|
||||
@@ -37,10 +42,14 @@ void nv2a_profile_increment(void)
|
||||
ts = now;
|
||||
frame_count = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void nv2a_profile_flip_stall(void)
|
||||
{
|
||||
#ifdef __ANDROID__
|
||||
return;
|
||||
#else
|
||||
int64_t now = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
|
||||
int64_t render_time = (now-g_nv2a_stats.last_flip_time)/1000;
|
||||
|
||||
@@ -51,6 +60,7 @@ void nv2a_profile_flip_stall(void)
|
||||
(g_nv2a_stats.frame_ptr + 1) % NV2A_PROF_NUM_FRAMES;
|
||||
g_nv2a_stats.frame_count++;
|
||||
memset(&g_nv2a_stats.frame_working, 0, sizeof(g_nv2a_stats.frame_working));
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *nv2a_profile_get_counter_name(unsigned int cnt)
|
||||
|
||||
@@ -1776,7 +1776,7 @@ void sdl2_gl_refresh(DisplayChangeListener *dcl)
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
const int64_t sleep_threshold = 500000; // 0.5ms — Android CFS scheduler jitter is ~0.2ms
|
||||
const int64_t sleep_threshold = 200000; // 0.2ms — modern Android CFS jitter is <0.1ms
|
||||
#elif !defined(_WIN32)
|
||||
const int64_t sleep_threshold = 2000000;
|
||||
#else
|
||||
@@ -1951,7 +1951,14 @@ static void *call_qemu_main(void *opaque)
|
||||
/* Note: only supports millisecond resolution on Windows */
|
||||
static void sleep_ns(int64_t ns)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
#ifdef __ANDROID__
|
||||
/* Use clock_nanosleep with relative time for better precision on Android.
|
||||
* CLOCK_MONOTONIC avoids wall-clock adjustments during sleep. */
|
||||
struct timespec sleep_delay;
|
||||
sleep_delay.tv_sec = ns / 1000000000LL;
|
||||
sleep_delay.tv_nsec = ns % 1000000000LL;
|
||||
clock_nanosleep(CLOCK_MONOTONIC, 0, &sleep_delay, NULL);
|
||||
#elif !defined(_WIN32)
|
||||
struct timespec sleep_delay, rem_delay;
|
||||
sleep_delay.tv_sec = ns / 1000000000LL;
|
||||
sleep_delay.tv_nsec = ns % 1000000000LL;
|
||||
|
||||
Reference in New Issue
Block a user