mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
fixed some bottlenecks various other fixes
This commit is contained in:
@@ -302,8 +302,8 @@ static void monitor_sink_cb(void *opaque, uint8_t *stream, int free_b)
|
||||
if (avail >= free_b) {
|
||||
break;
|
||||
}
|
||||
sleep_ns(500000);
|
||||
qemu_cond_broadcast(&s->cond);
|
||||
sleep_ns(500000);
|
||||
if (!runstate_is_running()) {
|
||||
memset(stream, 0, free_b);
|
||||
return;
|
||||
|
||||
@@ -28,6 +28,13 @@
|
||||
#include <math.h>
|
||||
#ifdef __ANDROID__
|
||||
#include <android/log.h>
|
||||
#include <EGL/egl.h>
|
||||
/* EGL_EGLEXT_PROTOTYPES enables KHR function declarations in eglext.h.
|
||||
* We use KHR variants because eglCreateSync (EGL 1.5) is only in
|
||||
* libEGL.so stubs from API 29+; the KHR equivalents exist from API 21. */
|
||||
#define EGL_EGLEXT_PROTOTYPES
|
||||
#include <EGL/eglext.h>
|
||||
#undef EGL_EGLEXT_PROTOTYPES
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
@@ -537,8 +544,23 @@ static void render_display(NV2AState *d, SurfaceBinding *surface)
|
||||
static void gl_fence(void)
|
||||
{
|
||||
#ifdef __ANDROID__
|
||||
/* Shared-context sync objects are still producing invalid-operation
|
||||
* failures on Adreno. Favor correctness over throughput here. */
|
||||
/* GL sync objects fail with GL_INVALID_OPERATION on Adreno when shared
|
||||
* across EGL contexts. EGL_KHR_fence_sync operates at the EGL level and
|
||||
* is not context-specific, so it is immune to this bug.
|
||||
* We use the KHR variants because they are present in libEGL.so from
|
||||
* API 21+; the EGL 1.5 core equivalents only appear from API 29. */
|
||||
EGLDisplay dpy = eglGetCurrentDisplay();
|
||||
if (dpy != EGL_NO_DISPLAY) {
|
||||
EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
|
||||
if (sync != EGL_NO_SYNC_KHR) {
|
||||
eglClientWaitSyncKHR(dpy, sync,
|
||||
EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
|
||||
EGL_FOREVER_KHR);
|
||||
eglDestroySyncKHR(dpy, sync);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* Fallback: EGL sync unavailable */
|
||||
glFinish();
|
||||
#else
|
||||
GLsync fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
|
||||
@@ -196,6 +196,13 @@ typedef struct PGRAPHGLState {
|
||||
#ifdef __ANDROID__
|
||||
GLuint gl_download_pbo;
|
||||
size_t gl_download_pbo_size;
|
||||
|
||||
/* Persistent scratch buffers for RGBA8 format conversion.
|
||||
* Avoids per-frame g_malloc/g_free in surface upload/download hot paths. */
|
||||
uint8_t *android_conv_buf; /* upload conversion (pgraph_gl_upload_surface_data) */
|
||||
size_t android_conv_buf_size;
|
||||
uint8_t *android_s2t_conv_buf; /* render-to-texture conversion */
|
||||
size_t android_s2t_conv_buf_size;
|
||||
#endif
|
||||
|
||||
TextureBinding *texture_binding[NV2A_MAX_TEXTURES];
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <android/log.h>
|
||||
#ifdef __aarch64__
|
||||
#include <arm_neon.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
@@ -211,22 +214,50 @@ static void android_surface_guest_to_rgba8(const SurfaceBinding *surface,
|
||||
break;
|
||||
case NV097_SET_SURFACE_FORMAT_COLOR_LE_X8R8G8B8_Z8R8G8B8:
|
||||
case NV097_SET_SURFACE_FORMAT_COLOR_LE_A8R8G8B8:
|
||||
{
|
||||
bool preserve_alpha = (surface->shape.color_format ==
|
||||
NV097_SET_SURFACE_FORMAT_COLOR_LE_A8R8G8B8);
|
||||
for (y = 0; y < height; y++) {
|
||||
const uint8_t *src_row = src + y * src_stride;
|
||||
uint8_t *dst_row = dst + y * width * 4;
|
||||
#ifdef __aarch64__
|
||||
/* vqtbl1q_u8: 16-byte shuffle, processes 4 pixels per instruction.
|
||||
* Permutation swaps R (byte 2) and B (byte 0) within each pixel. */
|
||||
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);
|
||||
/* For X8R8G8B8, force alpha=0xFF by ORing a pre-built mask. */
|
||||
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 px = width;
|
||||
while (px >= 4) {
|
||||
uint8x16_t v = vqtbl1q_u8(vld1q_u8(src_row), vperm);
|
||||
vst1q_u8(dst_row, vorrq_u8(v, valpha_mask));
|
||||
src_row += 16; dst_row += 16; px -= 4;
|
||||
}
|
||||
/* scalar tail for widths not divisible by 4 */
|
||||
while (px-- > 0) {
|
||||
dst_row[0] = src_row[2];
|
||||
dst_row[1] = src_row[1];
|
||||
dst_row[2] = src_row[0];
|
||||
dst_row[3] = preserve_alpha ? src_row[3] : 0xFF;
|
||||
src_row += 4; dst_row += 4;
|
||||
}
|
||||
#else
|
||||
for (x = 0; x < width; x++) {
|
||||
const uint8_t *pixel = src_row + x * 4;
|
||||
dst_row[x * 4 + 0] = pixel[2];
|
||||
dst_row[x * 4 + 1] = pixel[1];
|
||||
dst_row[x * 4 + 2] = pixel[0];
|
||||
dst_row[x * 4 + 3] =
|
||||
(surface->shape.color_format ==
|
||||
NV097_SET_SURFACE_FORMAT_COLOR_LE_A8R8G8B8)
|
||||
? pixel[3]
|
||||
: 0xFF;
|
||||
dst_row[x * 4 + 3] = preserve_alpha ? pixel[3] : 0xFF;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
@@ -867,20 +898,24 @@ static void render_surface_to_texture_slow(NV2AState *d,
|
||||
|
||||
#ifdef __ANDROID__
|
||||
if (android_surface_to_texture_rgba8_compatible(surface, texture_shape)) {
|
||||
uint8_t *upload_tmp = g_malloc(width * height * 4);
|
||||
PGRAPHGLState *r = pg->gl_renderer_state;
|
||||
size_t needed = (size_t)width * height * 4;
|
||||
if (needed > r->android_s2t_conv_buf_size) {
|
||||
r->android_s2t_conv_buf = g_realloc(r->android_s2t_conv_buf, needed);
|
||||
r->android_s2t_conv_buf_size = needed;
|
||||
}
|
||||
if (android_surface_to_texture_needs_guest_reinterpretation(
|
||||
surface, texture_shape)) {
|
||||
android_surface_guest_to_texture_rgba8(
|
||||
texture_shape, buf, width, height,
|
||||
width * surface->fmt.bytes_per_pixel, upload_tmp);
|
||||
width * surface->fmt.bytes_per_pixel, r->android_s2t_conv_buf);
|
||||
} else {
|
||||
android_surface_guest_to_rgba8(surface, buf, width, height,
|
||||
width * surface->fmt.bytes_per_pixel,
|
||||
upload_tmp);
|
||||
r->android_s2t_conv_buf);
|
||||
}
|
||||
glTexImage2D(texture->gl_target, 0, GL_RGBA8, width, height, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, upload_tmp);
|
||||
g_free(upload_tmp);
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, r->android_s2t_conv_buf);
|
||||
} else
|
||||
#endif
|
||||
glTexImage2D(texture->gl_target, 0, f->gl_internal_format, width, height, 0,
|
||||
@@ -2068,8 +2103,8 @@ void pgraph_gl_upload_surface_data(NV2AState *d, SurfaceBinding *surface,
|
||||
glBindTexture(GL_TEXTURE_2D, surface->gl_buffer);
|
||||
#ifdef __ANDROID__
|
||||
{
|
||||
PGRAPHGLState *r = pg->gl_renderer_state;
|
||||
const uint8_t *upload_buf = gl_read_buf;
|
||||
uint8_t *upload_tmp = NULL;
|
||||
GLint upload_ifmt;
|
||||
GLenum upload_fmt;
|
||||
GLenum upload_type;
|
||||
@@ -2077,15 +2112,18 @@ void pgraph_gl_upload_surface_data(NV2AState *d, SurfaceBinding *surface,
|
||||
android_surface_get_storage_format(surface, &upload_ifmt, &upload_fmt,
|
||||
&upload_type);
|
||||
if (android_surface_uses_rgba8_transfer(surface)) {
|
||||
upload_tmp = g_malloc(width * height * 4);
|
||||
size_t needed = (size_t)width * height * 4;
|
||||
if (needed > r->android_conv_buf_size) {
|
||||
r->android_conv_buf = g_realloc(r->android_conv_buf, needed);
|
||||
r->android_conv_buf_size = needed;
|
||||
}
|
||||
android_surface_guest_to_rgba8(surface, gl_read_buf, width, height,
|
||||
width * surface->fmt.bytes_per_pixel,
|
||||
upload_tmp);
|
||||
upload_buf = upload_tmp;
|
||||
r->android_conv_buf);
|
||||
upload_buf = r->android_conv_buf;
|
||||
}
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, upload_ifmt, width, height, 0,
|
||||
upload_fmt, upload_type, upload_buf);
|
||||
g_free(upload_tmp);
|
||||
}
|
||||
#else
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, surface->fmt.gl_internal_format, width,
|
||||
@@ -2577,6 +2615,10 @@ void pgraph_gl_init_surfaces(PGRAPHState *pg)
|
||||
#ifdef __ANDROID__
|
||||
glGenBuffers(1, &r->gl_download_pbo);
|
||||
r->gl_download_pbo_size = 0;
|
||||
r->android_conv_buf = NULL;
|
||||
r->android_conv_buf_size = 0;
|
||||
r->android_s2t_conv_buf = NULL;
|
||||
r->android_s2t_conv_buf_size = 0;
|
||||
#endif
|
||||
QTAILQ_INIT(&r->surfaces);
|
||||
r->downloads_pending = false;
|
||||
@@ -2622,6 +2664,12 @@ void pgraph_gl_finalize_surfaces(PGRAPHState *pg)
|
||||
r->gl_download_pbo = 0;
|
||||
r->gl_download_pbo_size = 0;
|
||||
}
|
||||
g_free(r->android_conv_buf);
|
||||
r->android_conv_buf = NULL;
|
||||
r->android_conv_buf_size = 0;
|
||||
g_free(r->android_s2t_conv_buf);
|
||||
r->android_s2t_conv_buf = NULL;
|
||||
r->android_s2t_conv_buf_size = 0;
|
||||
#endif
|
||||
|
||||
finalize_render_to_texture(pg);
|
||||
|
||||
@@ -62,6 +62,9 @@
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <android/log.h>
|
||||
#ifdef __aarch64__
|
||||
#include <arm_neon.h>
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#include "nvapi.h"
|
||||
@@ -1455,28 +1458,49 @@ void xb_surface_gl_create_texture(DisplaySurface *surface)
|
||||
uint8_t *converted = NULL;
|
||||
bool use_row_length = true;
|
||||
if (upload_format == GL_BGRA_EXT) {
|
||||
const int width = surface_width(surface);
|
||||
const int height = surface_height(surface);
|
||||
const int stride = surface_stride(surface);
|
||||
const uint8_t *src = (const uint8_t *)surface_data(surface);
|
||||
converted = g_malloc((size_t)width * height * 4);
|
||||
for (int y = 0; y < height; ++y) {
|
||||
const uint8_t *row = src + (size_t)y * stride;
|
||||
uint8_t *dst = converted + (size_t)y * width * 4;
|
||||
for (int x = 0; x < width; ++x) {
|
||||
const uint8_t b = row[x * 4 + 0];
|
||||
const uint8_t g = row[x * 4 + 1];
|
||||
const uint8_t r = row[x * 4 + 2];
|
||||
const uint8_t a = row[x * 4 + 3];
|
||||
dst[x * 4 + 0] = r;
|
||||
dst[x * 4 + 1] = g;
|
||||
dst[x * 4 + 2] = b;
|
||||
dst[x * 4 + 3] = a;
|
||||
if (g_android_gl_bgra_supported) {
|
||||
/* GL_EXT_texture_format_BGRA8888: upload native BGRA with no CPU
|
||||
* work. The spec requires internalformat == GL_BGRA_EXT too. */
|
||||
internal_format = GL_BGRA_EXT;
|
||||
/* upload_format stays GL_BGRA_EXT, use_row_length stays true */
|
||||
} else {
|
||||
/* Fallback: swizzle BGRA→RGBA on CPU before upload */
|
||||
const int width = surface_width(surface);
|
||||
const int height = surface_height(surface);
|
||||
const int stride = surface_stride(surface);
|
||||
const uint8_t *src = (const uint8_t *)surface_data(surface);
|
||||
converted = g_malloc((size_t)width * height * 4);
|
||||
for (int y = 0; y < height; ++y) {
|
||||
const uint8_t *row = src + (size_t)y * stride;
|
||||
uint8_t *dst = converted + (size_t)y * width * 4;
|
||||
#ifdef __aarch64__
|
||||
/* vqtbl1q_u8: 16-byte table lookup, processes 4 pixels/cycle */
|
||||
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);
|
||||
int px = width;
|
||||
while (px >= 4) {
|
||||
vst1q_u8(dst, vqtbl1q_u8(vld1q_u8(row), vperm));
|
||||
row += 16; dst += 16; px -= 4;
|
||||
}
|
||||
while (px-- > 0) {
|
||||
dst[0] = row[2]; dst[1] = row[1];
|
||||
dst[2] = row[0]; dst[3] = row[3];
|
||||
row += 4; dst += 4;
|
||||
}
|
||||
#else
|
||||
for (int x = 0; x < width; ++x) {
|
||||
dst[x * 4 + 0] = row[x * 4 + 2];
|
||||
dst[x * 4 + 1] = row[x * 4 + 1];
|
||||
dst[x * 4 + 2] = row[x * 4 + 0];
|
||||
dst[x * 4 + 3] = row[x * 4 + 3];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
upload_format = GL_RGBA;
|
||||
pixels = converted;
|
||||
use_row_length = false;
|
||||
}
|
||||
upload_format = GL_RGBA;
|
||||
pixels = converted;
|
||||
use_row_length = false;
|
||||
}
|
||||
if (use_row_length) {
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user