a little more stable and a little better performance.

This commit is contained in:
izzy2lost
2026-02-13 03:45:50 -05:00
parent 999e1a421c
commit 14f020dd3b
10 changed files with 357 additions and 88 deletions
+4 -2
View File
@@ -262,7 +262,7 @@ set(XEMU_CORE_DIRS
set(XEMU_CORE_SOURCES "")
foreach(dir ${XEMU_CORE_DIRS})
file(GLOB_RECURSE DIR_SOURCES
file(GLOB_RECURSE DIR_SOURCES CONFIGURE_DEPENDS
"${REPO_ROOT}/${dir}/*.c"
"${REPO_ROOT}/${dir}/*.cc"
"${REPO_ROOT}/${dir}/*.cpp"
@@ -270,7 +270,7 @@ foreach(dir ${XEMU_CORE_DIRS})
list(APPEND XEMU_CORE_SOURCES ${DIR_SOURCES})
endforeach()
file(GLOB ROOT_SOURCES
file(GLOB ROOT_SOURCES CONFIGURE_DEPENDS
"${REPO_ROOT}/*.c"
"${REPO_ROOT}/*.cc"
"${REPO_ROOT}/*.cpp"
@@ -375,6 +375,8 @@ list(FILTER XEMU_CORE_SOURCES EXCLUDE REGEX "hw[\\\\/]vfio-user[\\\\/].*\\.c$")
list(FILTER XEMU_CORE_SOURCES EXCLUDE REGEX "hw[\\\\/]virtio[\\\\/].*\\.c$")
list(FILTER XEMU_CORE_SOURCES EXCLUDE REGEX "hw[\\\\/]watchdog[\\\\/].*\\.c$")
list(FILTER XEMU_CORE_SOURCES EXCLUDE REGEX "hw[\\\\/]xbox[\\\\/]chihiro.*\\.c$")
list(FILTER XEMU_CORE_SOURCES EXCLUDE REGEX "hw[\\\\/]xbox[\\\\/]nv2a[\\\\/]pgraph[\\\\/]gl[\\\\/]gpuprops\\.c$")
list(FILTER XEMU_CORE_SOURCES EXCLUDE REGEX "hw[\\\\/]xbox[\\\\/]nv2a[\\\\/]pgraph[\\\\/]vk[\\\\/]gpuprops\\.c$")
if(NOT XEMU_ENABLE_VULKAN)
list(FILTER XEMU_CORE_SOURCES EXCLUDE REGEX "hw[\\\\/]xbox[\\\\/]nv2a[\\\\/]pgraph[\\\\/]vk[\\\\/].*\\.c$")
endif()
-4
View File
@@ -114,10 +114,6 @@ static void pgraph_gl_init(NV2AState *d, Error **errp)
gl_debug_initialize();
#endif
#ifdef __ANDROID__
pgraph_gl_determine_gpu_properties();
#endif
#ifdef __ANDROID__
/* DXT textures may be available via extension on Android. */
if (!glo_check_extension("GL_EXT_texture_compression_s3tc")) {
+30 -12
View File
@@ -402,22 +402,40 @@ static bool attempt_renderer_init(PGRAPHState *pg)
static void init_renderer(PGRAPHState *pg)
{
if (attempt_renderer_init(pg)) {
return; // Success
}
CONFIG_DISPLAY_RENDERER original_renderer = g_config.display.renderer;
CONFIG_DISPLAY_RENDERER default_renderer = get_default_renderer();
if (default_renderer != g_config.display.renderer) {
g_config.display.renderer = default_renderer;
if (attempt_renderer_init(pg)) {
g_autofree gchar *msg = g_strdup_printf(
"Switched to default renderer: %s", pg->renderer->name);
xemu_queue_notification(msg);
return;
CONFIG_DISPLAY_RENDERER attempts[CONFIG_DISPLAY_RENDERER__COUNT];
int attempt_count = 0;
attempts[attempt_count++] = original_renderer;
if (default_renderer != original_renderer) {
attempts[attempt_count++] = default_renderer;
}
for (int i = 0; i < CONFIG_DISPLAY_RENDERER__COUNT; i++) {
CONFIG_DISPLAY_RENDERER renderer = (CONFIG_DISPLAY_RENDERER)i;
bool already_added = false;
for (int j = 0; j < attempt_count; j++) {
if (attempts[j] == renderer) {
already_added = true;
break;
}
}
if (!already_added && renderers[renderer]) {
attempts[attempt_count++] = renderer;
}
}
// FIXME: Try others
for (int i = 0; i < attempt_count; i++) {
g_config.display.renderer = attempts[i];
if (attempt_renderer_init(pg)) {
if (attempts[i] != original_renderer) {
g_autofree gchar *msg = g_strdup_printf(
"Switched renderer to %s", pg->renderer->name);
xemu_queue_notification(msg);
}
return;
}
}
fprintf(stderr, "Fatal error: cannot initialize renderer\n");
exit(1);
+99 -14
View File
@@ -19,7 +19,26 @@
#include "renderer.h"
static void create_buffer(PGRAPHState *pg, StorageBuffer *buffer)
#ifdef __ANDROID__
#include <android/log.h>
#endif
static const char *const buffer_names[BUFFER_COUNT] = {
"BUFFER_STAGING_DST",
"BUFFER_STAGING_SRC",
"BUFFER_COMPUTE_DST",
"BUFFER_COMPUTE_SRC",
"BUFFER_INDEX",
"BUFFER_INDEX_STAGING",
"BUFFER_VERTEX_RAM",
"BUFFER_VERTEX_INLINE",
"BUFFER_VERTEX_INLINE_STAGING",
"BUFFER_UNIFORM",
"BUFFER_UNIFORM_STAGING",
};
static bool create_buffer(PGRAPHState *pg, StorageBuffer *buffer,
const char *name, Error **errp)
{
PGRAPHVkState *r = pg->vk_renderer_state;
@@ -29,41 +48,75 @@ static void create_buffer(PGRAPHState *pg, StorageBuffer *buffer)
.usage = buffer->usage,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
};
VK_CHECK(vmaCreateBuffer(r->allocator, &buffer_create_info,
&buffer->alloc_info, &buffer->buffer,
&buffer->allocation, NULL));
VkResult result = vmaCreateBuffer(r->allocator, &buffer_create_info,
&buffer->alloc_info, &buffer->buffer,
&buffer->allocation, NULL);
if (result != VK_SUCCESS) {
error_setg(errp, "Failed to create Vulkan buffer %s (%zu bytes): %d",
name, buffer->buffer_size, result);
return false;
}
return true;
}
static void destroy_buffer(PGRAPHState *pg, StorageBuffer *buffer)
{
PGRAPHVkState *r = pg->vk_renderer_state;
if (buffer->buffer == VK_NULL_HANDLE && buffer->allocation == VK_NULL_HANDLE) {
return;
}
vmaDestroyBuffer(r->allocator, buffer->buffer, buffer->allocation);
buffer->buffer = VK_NULL_HANDLE;
buffer->allocation = VK_NULL_HANDLE;
}
void pgraph_vk_init_buffers(NV2AState *d)
bool pgraph_vk_init_buffers(NV2AState *d, Error **errp)
{
PGRAPHState *pg = &d->pgraph;
PGRAPHVkState *r = pg->vk_renderer_state;
// FIXME: Profile buffer sizes
const size_t mib = 1024 * 1024;
size_t vram_size = memory_region_size(d->vram);
size_t staging_size = vram_size;
if (staging_size < (16 * mib)) {
staging_size = 16 * mib;
}
size_t compute_size = vram_size * 2;
if (compute_size < (64 * mib)) {
compute_size = 64 * mib;
}
#ifdef __ANDROID__
if (compute_size > (64 * mib)) {
compute_size = 64 * mib;
}
#else
if (compute_size > (256 * mib)) {
compute_size = 256 * mib;
}
#endif
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "xemu-android",
"vk buffer init: vram=%zu staging=%zu compute=%zu",
vram_size, staging_size, compute_size);
#endif
VmaAllocationCreateInfo host_alloc_create_info = {
.usage = VMA_MEMORY_USAGE_AUTO_PREFER_HOST,
.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT |
VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT,
.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT,
};
VmaAllocationCreateInfo device_alloc_create_info = {
.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,
.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT
.flags = 0,
};
r->storage_buffers[BUFFER_STAGING_DST] = (StorageBuffer){
.alloc_info = host_alloc_create_info,
.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT,
.buffer_size = 4096 * 4096 * 4,
.buffer_size = staging_size,
};
r->storage_buffers[BUFFER_STAGING_SRC] = (StorageBuffer){
@@ -76,7 +129,7 @@ void pgraph_vk_init_buffers(NV2AState *d)
.alloc_info = device_alloc_create_info,
.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT |
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
.buffer_size = (1024 * 10) * (1024 * 10) * 8,
.buffer_size = compute_size,
};
r->storage_buffers[BUFFER_COMPUTE_SRC] = (StorageBuffer){
@@ -108,6 +161,10 @@ void pgraph_vk_init_buffers(NV2AState *d)
r->bitmap_size = memory_region_size(d->vram) / 4096;
r->uploaded_bitmap = bitmap_new(r->bitmap_size);
if (!r->uploaded_bitmap) {
error_setg(errp, "Failed to allocate uploaded surface bitmap");
return false;
}
bitmap_clear(r->uploaded_bitmap, 0, r->bitmap_size);
r->storage_buffers[BUFFER_VERTEX_INLINE] = (StorageBuffer){
@@ -138,7 +195,14 @@ void pgraph_vk_init_buffers(NV2AState *d)
};
for (int i = 0; i < BUFFER_COUNT; i++) {
create_buffer(pg, &r->storage_buffers[i]);
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "xemu-android",
"vk buffer init: create %s size=%zu",
buffer_names[i], r->storage_buffers[i].buffer_size);
#endif
if (!create_buffer(pg, &r->storage_buffers[i], buffer_names[i], errp)) {
goto fail;
}
}
// FIXME: Add fallback path for device using host mapped memory
@@ -149,12 +213,33 @@ void pgraph_vk_init_buffers(NV2AState *d)
BUFFER_UNIFORM_STAGING };
for (int i = 0; i < ARRAY_SIZE(buffers_to_map); i++) {
VK_CHECK(vmaMapMemory(
r->allocator, r->storage_buffers[buffers_to_map[i]].allocation,
(void **)&r->storage_buffers[buffers_to_map[i]].mapped));
int idx = buffers_to_map[i];
VkResult result = vmaMapMemory(
r->allocator, r->storage_buffers[idx].allocation,
(void **)&r->storage_buffers[idx].mapped);
if (result != VK_SUCCESS) {
error_setg(errp, "Failed to map Vulkan buffer %s (%zu bytes): %d",
buffer_names[idx], r->storage_buffers[idx].buffer_size,
result);
goto fail;
}
}
pgraph_prim_rewrite_init(&r->prim_rewrite_buf);
return true;
fail:
for (int i = 0; i < BUFFER_COUNT; i++) {
if (r->storage_buffers[i].mapped) {
vmaUnmapMemory(r->allocator, r->storage_buffers[i].allocation);
r->storage_buffers[i].mapped = NULL;
}
destroy_buffer(pg, &r->storage_buffers[i]);
}
g_free(r->uploaded_bitmap);
r->uploaded_bitmap = NULL;
r->bitmap_size = 0;
return false;
}
void pgraph_vk_finalize_buffers(NV2AState *d)
+40 -27
View File
@@ -590,12 +590,12 @@ static void destroy_current_display_image(PGRAPHState *pg)
destroy_frame_buffer(pg);
#if HAVE_EXTERNAL_MEMORY
if (p_glDeleteMemoryObjectsEXT) {
if (d->gl_texture_id && p_glDeleteMemoryObjectsEXT) {
glDeleteTextures(1, &d->gl_texture_id);
}
d->gl_texture_id = 0;
if (p_glDeleteMemoryObjectsEXT) {
if (d->gl_memory_obj && p_glDeleteMemoryObjectsEXT) {
p_glDeleteMemoryObjectsEXT(1, &d->gl_memory_obj);
}
d->gl_memory_obj = 0;
@@ -630,24 +630,33 @@ static bool create_display_image(PGRAPHState *pg, int width, int height)
destroy_current_display_image(pg);
}
#if HAVE_EXTERNAL_MEMORY
const GLint gl_internal_format = GL_RGBA8;
#endif
bool use_optimal_tiling = true;
#if HAVE_EXTERNAL_MEMORY
bool use_external_memory = d->use_external_memory;
#else
bool use_external_memory = false;
#endif
#if HAVE_EXTERNAL_MEMORY
GLint num_tiling_types;
glGetInternalformativ(GL_TEXTURE_2D, gl_internal_format,
GL_NUM_TILING_TYPES_EXT, 1, &num_tiling_types);
// XXX: Apparently on AMD GL_OPTIMAL_TILING_EXT is reported to be
// supported, but doesn't work? On nVidia, GL_LINEAR_TILING_EXT may not
// be supported so we must use optimal. Default to optimal unless
// linear is explicitly specified...
GLint tiling_types[num_tiling_types];
glGetInternalformativ(GL_TEXTURE_2D, gl_internal_format,
GL_TILING_TYPES_EXT, num_tiling_types, tiling_types);
for (int i = 0; i < num_tiling_types; i++) {
if (tiling_types[i] == GL_LINEAR_TILING_EXT) {
use_optimal_tiling = false;
break;
if (use_external_memory) {
GLint num_tiling_types;
glGetInternalformativ(GL_TEXTURE_2D, gl_internal_format,
GL_NUM_TILING_TYPES_EXT, 1, &num_tiling_types);
// XXX: Apparently on AMD GL_OPTIMAL_TILING_EXT is reported to be
// supported, but doesn't work? On nVidia, GL_LINEAR_TILING_EXT may not
// be supported so we must use optimal. Default to optimal unless
// linear is explicitly specified...
GLint tiling_types[num_tiling_types];
glGetInternalformativ(GL_TEXTURE_2D, gl_internal_format,
GL_TILING_TYPES_EXT, num_tiling_types, tiling_types);
for (int i = 0; i < num_tiling_types; i++) {
if (tiling_types[i] == GL_LINEAR_TILING_EXT) {
use_optimal_tiling = false;
break;
}
}
}
#endif
@@ -683,7 +692,11 @@ static bool create_display_image(PGRAPHState *pg, int width, int height)
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR,
#endif
};
image_create_info.pNext = &external_memory_image_create_info;
if (use_external_memory) {
image_create_info.pNext = &external_memory_image_create_info;
} else {
image_create_info.pNext = NULL;
}
VkResult result = vkCreateImage(r->device, &image_create_info, NULL, &d->image);
if (result != VK_SUCCESS) {
@@ -739,15 +752,18 @@ static bool create_display_image(PGRAPHState *pg, int width, int height)
#endif
,
};
void *alloc_p_next = &export_memory_alloc_info;
void *alloc_p_next = NULL;
VkMemoryDedicatedAllocateInfo dedicated_alloc_info = {
.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
.image = d->image,
};
if (dedicated_requirements.requiresDedicatedAllocation == VK_TRUE) {
dedicated_alloc_info.pNext = alloc_p_next;
alloc_p_next = &dedicated_alloc_info;
}
if (use_external_memory) {
export_memory_alloc_info.pNext = alloc_p_next;
alloc_p_next = &export_memory_alloc_info;
}
alloc_info.pNext = alloc_p_next;
result = vkAllocateMemory(r->device, &alloc_info, NULL, &d->memory);
@@ -793,17 +809,13 @@ static bool create_display_image(PGRAPHState *pg, int width, int height)
}
#if HAVE_EXTERNAL_MEMORY
if (!load_gl_external_memory_symbols()) {
if (use_external_memory && !load_gl_external_memory_symbols()) {
fprintf(stderr, "Vulkan display: GL_EXT_memory_object not available\n");
vkDestroyImageView(r->device, d->image_view, NULL);
d->image_view = VK_NULL_HANDLE;
vkFreeMemory(r->device, d->memory, NULL);
d->memory = VK_NULL_HANDLE;
vkDestroyImage(r->device, d->image, NULL);
d->image = VK_NULL_HANDLE;
return false;
d->use_external_memory = false;
use_external_memory = false;
}
if (use_external_memory) {
#ifdef WIN32
VkMemoryGetWin32HandleInfoKHR handle_info = {
@@ -872,6 +884,7 @@ static bool create_display_image(PGRAPHState *pg, int width, int height)
d->image = VK_NULL_HANDLE;
return false;
}
}
#endif // HAVE_EXTERNAL_MEMORY
+69 -8
View File
@@ -179,6 +179,12 @@ static bool create_instance(PGRAPHState *pg, Error **errp)
add_optional_instance_extension_names(pg, available_extensions,
enabled_extension_names);
const char *const *enabled_instance_extension_names = NULL;
if (enabled_extension_names->len > 0) {
enabled_instance_extension_names =
&g_array_index(enabled_extension_names, const char *, 0);
}
fprintf(stderr, "Enabled instance extensions:\n");
for (int i = 0; i < enabled_extension_names->len; i++) {
fprintf(stderr, "- %s\n",
@@ -189,8 +195,7 @@ static bool create_instance(PGRAPHState *pg, Error **errp)
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
.pApplicationInfo = &app_info,
.enabledExtensionCount = enabled_extension_names->len,
.ppEnabledExtensionNames =
&g_array_index(enabled_extension_names, const char *, 0),
.ppEnabledExtensionNames = enabled_instance_extension_names,
};
enable_validation = g_config.display.vulkan.validation_layers;
@@ -445,6 +450,12 @@ static bool create_logical_device(PGRAPHState *pg, Error **errp)
add_optional_device_extension_names(pg, available_extensions,
enabled_extension_names);
const char *const *enabled_device_extension_names = NULL;
if (enabled_extension_names->len > 0) {
enabled_device_extension_names =
&g_array_index(enabled_extension_names, const char *, 0);
}
fprintf(stderr, "Enabled device extensions:\n");
for (int i = 0; i < enabled_extension_names->len; i++) {
fprintf(stderr, "- %s\n",
@@ -557,8 +568,7 @@ static bool create_logical_device(PGRAPHState *pg, Error **errp)
.pQueueCreateInfos = &queue_create_info,
.pEnabledFeatures = &r->enabled_physical_device_features,
.enabledExtensionCount = enabled_extension_names->len,
.ppEnabledExtensionNames =
&g_array_index(enabled_extension_names, const char *, 0),
.ppEnabledExtensionNames = enabled_device_extension_names,
.pNext = next_struct,
};
@@ -567,12 +577,20 @@ static bool create_logical_device(PGRAPHState *pg, Error **errp)
device_create_info.ppEnabledLayerNames = validation_layers;
}
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "xemu-android",
"vk init stage: vkCreateDevice");
#endif
result = vkCreateDevice(r->physical_device, &device_create_info, NULL,
&r->device);
if (result != VK_SUCCESS) {
error_setg(errp, "Failed to create logical device (%d)", result);
return false;
}
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "xemu-android",
"vk init stage: vkCreateDevice done");
#endif
vkGetDeviceQueue(r->device, indices.queue_family, 0, &r->queue);
return true;
@@ -648,21 +666,64 @@ static bool init_allocator(PGRAPHState *pg, Error **errp)
.pVulkanFunctions = &vulkanFunctions,
};
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "xemu-android",
"vk init stage: vmaCreateAllocator");
#endif
result = vmaCreateAllocator(&create_info, &r->allocator);
if (result != VK_SUCCESS) {
error_setg(errp, "vmaCreateAllocator failed");
return false;
}
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "xemu-android",
"vk init stage: vmaCreateAllocator done");
#endif
return true;
}
void pgraph_vk_init_instance(PGRAPHState *pg, Error **errp)
{
if (create_instance(pg, errp) &&
select_physical_device(pg, errp) &&
create_logical_device(pg, errp) &&
init_allocator(pg, errp)) {
bool ok = false;
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "xemu-android",
"vk init stage: create_instance");
#endif
if (!create_instance(pg, errp)) {
goto done;
}
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "xemu-android",
"vk init stage: select_physical_device");
#endif
if (!select_physical_device(pg, errp)) {
goto done;
}
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "xemu-android",
"vk init stage: create_logical_device");
#endif
if (!create_logical_device(pg, errp)) {
goto done;
}
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "xemu-android",
"vk init stage: init_allocator");
#endif
if (!init_allocator(pg, errp)) {
goto done;
}
ok = true;
done:
if (ok) {
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "xemu-android",
"vk init stage: complete");
#endif
return;
}
+79 -13
View File
@@ -52,6 +52,7 @@ static void pgraph_vk_init(NV2AState *d, Error **errp)
pg->vk_renderer_state = (PGRAPHVkState *)g_malloc0(sizeof(PGRAPHVkState));
#if HAVE_EXTERNAL_MEMORY
bool use_external_memory = false;
#ifdef __ANDROID__
if (!g_gl_context) {
// On Android, we need to ensure the main GL context is accessible
@@ -65,15 +66,22 @@ static void pgraph_vk_init(NV2AState *d, Error **errp)
}
}
#endif
if (!g_gl_context) {
error_setg(errp, "Failed to create GL offscreen context for Vulkan display");
return;
if (g_gl_context) {
glo_set_current(g_gl_context);
use_external_memory = pgraph_vk_gl_external_memory_available();
}
glo_set_current(g_gl_context);
if (!pgraph_vk_gl_external_memory_available()) {
error_setg(errp, "GL_EXT_memory_object not available for Vulkan display");
return;
if (!use_external_memory) {
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_WARN, "xemu-android",
"pgraph_vk_init: external memory interop unavailable, using download fallback");
#endif
}
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "xemu-android",
"pgraph_vk_init: external memory interop=%s",
use_external_memory ? "enabled" : "disabled");
#endif
pg->vk_renderer_state->display.use_external_memory = use_external_memory;
#endif
pgraph_vk_debug_init();
@@ -83,19 +91,66 @@ static void pgraph_vk_init(NV2AState *d, Error **errp)
return;
}
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "xemu-android",
"vk init stage: command_buffers");
#endif
pgraph_vk_init_command_buffers(pg);
pgraph_vk_init_buffers(d);
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "xemu-android",
"vk init stage: buffers");
#endif
if (!pgraph_vk_init_buffers(d, errp)) {
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_ERROR, "xemu-android",
"vk init stage: buffers failed");
#endif
return;
}
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "xemu-android",
"vk init stage: surfaces");
#endif
pgraph_vk_init_surfaces(pg);
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "xemu-android",
"vk init stage: shaders");
#endif
pgraph_vk_init_shaders(pg);
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "xemu-android",
"vk init stage: pipelines");
#endif
pgraph_vk_init_pipelines(pg);
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "xemu-android",
"vk init stage: textures");
#endif
pgraph_vk_init_textures(pg);
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "xemu-android",
"vk init stage: reports");
#endif
pgraph_vk_init_reports(pg);
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "xemu-android",
"vk init stage: compute");
#endif
pgraph_vk_init_compute(pg);
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "xemu-android",
"vk init stage: display");
#endif
pgraph_vk_init_display(pg);
pgraph_vk_update_vertex_ram_buffer(&d->pgraph, 0, d->vram_ptr,
memory_region_size(d->vram));
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "xemu-android",
"vk init stage: renderer_ready");
#endif
}
static void pgraph_vk_finalize(NV2AState *d)
@@ -146,7 +201,13 @@ static void pgraph_vk_flush(NV2AState *d)
static void pgraph_vk_sync(NV2AState *d)
{
PGRAPHState *pg = &d->pgraph;
#if HAVE_EXTERNAL_MEMORY
if (pg->vk_renderer_state->display.use_external_memory) {
pgraph_vk_render_display(pg);
}
#else
pgraph_vk_render_display(pg);
#endif
qatomic_set(&d->pgraph.sync_pending, false);
qemu_event_set(&d->pgraph.sync_complete);
@@ -230,12 +291,17 @@ static int pgraph_vk_get_framebuffer_surface(NV2AState *d)
surface->frame_time = pg->frame_time;
#if HAVE_EXTERNAL_MEMORY
qemu_event_reset(&d->pgraph.sync_complete);
qatomic_set(&pg->sync_pending, true);
pfifo_kick(d);
if (r->display.use_external_memory) {
qemu_event_reset(&d->pgraph.sync_complete);
qatomic_set(&pg->sync_pending, true);
pfifo_kick(d);
qemu_mutex_unlock(&d->pfifo.lock);
qemu_event_wait(&d->pgraph.sync_complete);
return r->display.gl_texture_id;
}
qemu_mutex_unlock(&d->pfifo.lock);
qemu_event_wait(&d->pgraph.sync_complete);
return r->display.gl_texture_id;
pgraph_vk_wait_for_surface_download(surface);
return 0;
#else
qemu_mutex_unlock(&d->pfifo.lock);
pgraph_vk_wait_for_surface_download(surface);
+2 -1
View File
@@ -286,6 +286,7 @@ typedef struct PGRAPHVkDisplayState {
int width, height;
int draw_time;
bool use_external_memory;
// OpenGL Interop
#ifdef WIN32
@@ -470,7 +471,7 @@ void pgraph_vk_unref_shader_module(PGRAPHVkState *r, ShaderModuleInfo *info);
void pgraph_vk_destroy_shader_module(PGRAPHVkState *r, ShaderModuleInfo *info);
// buffer.c
void pgraph_vk_init_buffers(NV2AState *d);
bool pgraph_vk_init_buffers(NV2AState *d, Error **errp);
void pgraph_vk_finalize_buffers(NV2AState *d);
bool pgraph_vk_buffer_has_space_for(PGRAPHState *pg, int index,
VkDeviceSize size,
+22 -3
View File
@@ -496,8 +496,19 @@ static void download_surface(NV2AState *d, SurfaceBinding *surface, bool force)
void pgraph_vk_wait_for_surface_download(SurfaceBinding *surface)
{
NV2AState *d = g_nv2a;
bool require_download = qatomic_read(&surface->draw_dirty);
if (qatomic_read(&surface->draw_dirty)) {
#ifdef __ANDROID__
/*
* Android Vulkan currently presents through the CPU/VGA fallback path.
* Force framebuffer surface download so fallback upload sees fresh pixels.
*/
if (!d->pgraph.vk_renderer_state->display.use_external_memory) {
require_download = true;
}
#endif
if (require_download) {
qemu_mutex_lock(&d->pfifo.lock);
qemu_event_reset(&d->pgraph.vk_renderer_state->downloads_complete);
qatomic_set(&surface->download_pending, true);
@@ -1699,7 +1710,11 @@ void pgraph_vk_init_surfaces(PGRAPHState *pg)
bool color_formats_supported = check_surface_internal_formats_supported(
r, kelvin_surface_color_format_vk_map,
ARRAY_SIZE(kelvin_surface_color_format_vk_map));
assert(color_formats_supported);
if (!color_formats_supported) {
fprintf(stderr,
"Warning: Some Vulkan surface color formats are unsupported; "
"continuing with best-effort mapping.\n");
}
// Check if the device supports preferred VK_FORMAT_D24_UNORM_S8_UINT
// format, fall back to D32_SFLOAT_S8_UINT otherwise.
@@ -1713,7 +1728,11 @@ void pgraph_vk_init_surfaces(PGRAPHState *pg)
r->kelvin_surface_zeta_vk_map[NV097_SET_SURFACE_FORMAT_ZETA_Z24S8] =
zeta_d32_sfloat_s8_uint;
} else {
assert(!"No suitable depth-stencil format supported");
fprintf(stderr,
"Warning: No suitable Vulkan Z24S8 depth-stencil format; "
"falling back to Z16 mapping.\n");
r->kelvin_surface_zeta_vk_map[NV097_SET_SURFACE_FORMAT_ZETA_Z24S8] =
zeta_d16;
}
QTAILQ_INIT(&r->surfaces);
+12 -4
View File
@@ -224,7 +224,8 @@ static bool android_blit_init(void)
"uniform sampler2D u_tex;\n"
"out vec4 out_Color;\n"
"void main() {\n"
" out_Color = texture(u_tex, v_uv);\n"
" vec4 c = texture(u_tex, v_uv);\n"
" out_Color = vec4(c.rgb, 1.0);\n"
"}\n";
GLuint vshader = android_gl_compile_shader(GL_VERTEX_SHADER, vs);
@@ -292,6 +293,11 @@ static void android_blit_frame(GLuint tex, bool flip)
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, w, h);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDisable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glDisable(GL_SCISSOR_TEST);
glUseProgram(g_android_blit_prog);
glUniform1i(g_android_blit_tex_loc, 0);
glUniform1i(g_android_blit_flip_loc, flip ? 1 : 0);
@@ -1412,10 +1418,12 @@ void xb_surface_gl_create_texture(DisplaySurface *surface)
}
glBindTexture(GL_TEXTURE_2D, surface->texture);
const void *pixels = surface_data(surface);
GLenum upload_format = surface->glformat;
GLenum upload_type = surface->gltype;
#ifdef __ANDROID__
uint8_t *converted = NULL;
bool use_row_length = true;
if (surface->glformat == GL_BGRA_EXT) {
if (upload_format == GL_BGRA_EXT) {
const int width = surface_width(surface);
const int height = surface_height(surface);
const int stride = surface_stride(surface);
@@ -1435,7 +1443,7 @@ void xb_surface_gl_create_texture(DisplaySurface *surface)
dst[x * 4 + 3] = a;
}
}
surface->glformat = GL_RGBA;
upload_format = GL_RGBA;
pixels = converted;
use_row_length = false;
}
@@ -1449,7 +1457,7 @@ void xb_surface_gl_create_texture(DisplaySurface *surface)
glTexImage2D(GL_TEXTURE_2D, 0, internal_format,
surface_width(surface),
surface_height(surface),
0, surface->glformat, surface->gltype,
0, upload_format, upload_type,
pixels);
#ifdef __ANDROID__
if (use_row_length) {