mirror of https://github.com/xemu-project/xemu.git
nv2a: Handle renderer init errors more gracefully
This commit is contained in:
parent
c1bbe39f22
commit
25afb8603d
|
@ -33,7 +33,7 @@ static void early_context_init(void)
|
||||||
g_nv2a_context_display = glo_context_create();
|
g_nv2a_context_display = glo_context_create();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pgraph_gl_init(NV2AState *d)
|
static void pgraph_gl_init(NV2AState *d, Error **errp)
|
||||||
{
|
{
|
||||||
PGRAPHState *pg = &d->pgraph;
|
PGRAPHState *pg = &d->pgraph;
|
||||||
|
|
||||||
|
|
|
@ -111,7 +111,7 @@ static void pgraph_null_surface_update(NV2AState *d, bool upload,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pgraph_null_init(NV2AState *d)
|
static void pgraph_null_init(NV2AState *d, Error **errp)
|
||||||
{
|
{
|
||||||
PGRAPHState *pg = &d->pgraph;
|
PGRAPHState *pg = &d->pgraph;
|
||||||
pg->null_renderer_state = NULL;
|
pg->null_renderer_state = NULL;
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "../nv2a_int.h"
|
#include "../nv2a_int.h"
|
||||||
|
#include "ui/xemu-notifications.h"
|
||||||
#include "ui/xemu-settings.h"
|
#include "ui/xemu-settings.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "swizzle.h"
|
#include "swizzle.h"
|
||||||
|
@ -238,8 +239,6 @@ void pgraph_init(NV2AState *d)
|
||||||
}
|
}
|
||||||
|
|
||||||
pgraph_clear_dirty_reg_map(pg);
|
pgraph_clear_dirty_reg_map(pg);
|
||||||
|
|
||||||
pg->renderer = renderers[g_config.display.renderer];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pgraph_clear_dirty_reg_map(PGRAPHState *pg)
|
void pgraph_clear_dirty_reg_map(PGRAPHState *pg)
|
||||||
|
@ -247,13 +246,6 @@ void pgraph_clear_dirty_reg_map(PGRAPHState *pg)
|
||||||
memset(pg->regs_dirty, 0, sizeof(pg->regs_dirty));
|
memset(pg->regs_dirty, 0, sizeof(pg->regs_dirty));
|
||||||
}
|
}
|
||||||
|
|
||||||
void pgraph_init_thread(NV2AState *d)
|
|
||||||
{
|
|
||||||
if (d->pgraph.renderer->ops.init) {
|
|
||||||
d->pgraph.renderer->ops.init(d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static CONFIG_DISPLAY_RENDERER get_default_renderer(void)
|
static CONFIG_DISPLAY_RENDERER get_default_renderer(void)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_OPENGL
|
#ifdef CONFIG_OPENGL
|
||||||
|
@ -293,6 +285,59 @@ void nv2a_context_init(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool attempt_renderer_init(PGRAPHState *pg)
|
||||||
|
{
|
||||||
|
NV2AState *d = container_of(pg, NV2AState, pgraph);
|
||||||
|
|
||||||
|
pg->renderer = renderers[g_config.display.renderer];
|
||||||
|
if (!pg->renderer) {
|
||||||
|
xemu_queue_error_message("Configured renderer not available");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error *local_err = NULL;
|
||||||
|
if (pg->renderer->ops.init) {
|
||||||
|
pg->renderer->ops.init(d, &local_err);
|
||||||
|
}
|
||||||
|
if (local_err) {
|
||||||
|
const char *msg = error_get_pretty(local_err);
|
||||||
|
xemu_queue_error_message(msg);
|
||||||
|
error_free(local_err);
|
||||||
|
local_err = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_renderer(PGRAPHState *pg)
|
||||||
|
{
|
||||||
|
if (attempt_renderer_init(pg)) {
|
||||||
|
return; // Success
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: Try others
|
||||||
|
|
||||||
|
fprintf(stderr, "Fatal error: cannot initialize renderer\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pgraph_init_thread(NV2AState *d)
|
||||||
|
{
|
||||||
|
init_renderer(&d->pgraph);
|
||||||
|
}
|
||||||
|
|
||||||
void pgraph_destroy(PGRAPHState *pg)
|
void pgraph_destroy(PGRAPHState *pg)
|
||||||
{
|
{
|
||||||
NV2AState *d = container_of(pg, NV2AState, pgraph);
|
NV2AState *d = container_of(pg, NV2AState, pgraph);
|
||||||
|
@ -2919,12 +2964,7 @@ void pgraph_process_pending(NV2AState *d)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Handle missing renderer, init errors
|
init_renderer(pg);
|
||||||
pg->renderer = renderers[g_config.display.renderer];
|
|
||||||
|
|
||||||
if (pg->renderer->ops.init) {
|
|
||||||
pg->renderer->ops.init(d);
|
|
||||||
}
|
|
||||||
|
|
||||||
qemu_mutex_unlock(&d->pgraph.renderer_lock);
|
qemu_mutex_unlock(&d->pgraph.renderer_lock);
|
||||||
qemu_mutex_unlock(&d->pgraph.lock);
|
qemu_mutex_unlock(&d->pgraph.lock);
|
||||||
|
|
|
@ -100,7 +100,7 @@ typedef struct PGRAPHRenderer {
|
||||||
const char *name;
|
const char *name;
|
||||||
struct {
|
struct {
|
||||||
void (*early_context_init)(void);
|
void (*early_context_init)(void);
|
||||||
void (*init)(NV2AState *d);
|
void (*init)(NV2AState *d, Error **errp);
|
||||||
void (*finalize)(NV2AState *d);
|
void (*finalize)(NV2AState *d);
|
||||||
void (*clear_report_value)(NV2AState *d);
|
void (*clear_report_value)(NV2AState *d);
|
||||||
void (*clear_surface)(NV2AState *d, uint32_t parameter);
|
void (*clear_surface)(NV2AState *d, uint32_t parameter);
|
||||||
|
|
|
@ -98,19 +98,23 @@ static bool check_validation_layer_support(void)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SDL_Window *create_window(void)
|
static void create_window(PGRAPHVkState *r, Error **errp)
|
||||||
{
|
{
|
||||||
SDL_Window *window = SDL_CreateWindow(
|
r->window = SDL_CreateWindow(
|
||||||
"SDL Offscreen Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
"SDL Offscreen Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
||||||
640, 480, SDL_WINDOW_VULKAN | SDL_WINDOW_HIDDEN);
|
640, 480, SDL_WINDOW_VULKAN | SDL_WINDOW_HIDDEN);
|
||||||
|
|
||||||
if (window == NULL) {
|
if (r->window == NULL) {
|
||||||
fprintf(stderr, "%s: Failed to create window\n", __func__);
|
error_setg(errp, "SDL_CreateWindow failed: %s", SDL_GetError());
|
||||||
SDL_Quit();
|
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return window;
|
static void destroy_window(PGRAPHVkState *r)
|
||||||
|
{
|
||||||
|
if (r->window) {
|
||||||
|
SDL_DestroyWindow(r->window);
|
||||||
|
r->window = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static VkExtensionPropertiesArray *
|
static VkExtensionPropertiesArray *
|
||||||
|
@ -199,13 +203,22 @@ add_optional_instance_extension_names(PGRAPHState *pg,
|
||||||
VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void create_instance(PGRAPHState *pg)
|
static bool create_instance(PGRAPHState *pg, Error **errp)
|
||||||
{
|
{
|
||||||
PGRAPHVkState *r = pg->vk_renderer_state;
|
PGRAPHVkState *r = pg->vk_renderer_state;
|
||||||
|
VkResult result;
|
||||||
|
|
||||||
r->window = create_window();
|
create_window(r, errp);
|
||||||
|
if (*errp) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
VK_CHECK(volkInitialize());
|
result = volkInitialize();
|
||||||
|
if (result != VK_SUCCESS) {
|
||||||
|
error_setg(errp, "volkInitialize failed");
|
||||||
|
destroy_window(r);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
VkApplicationInfo app_info = {
|
VkApplicationInfo app_info = {
|
||||||
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
||||||
|
@ -234,14 +247,19 @@ static void create_instance(PGRAPHState *pg)
|
||||||
all_required_extensions_available = false;
|
all_required_extensions_available = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(all_required_extensions_available);
|
|
||||||
|
if (!all_required_extensions_available) {
|
||||||
|
error_setg(errp, "Required instance extensions not available");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
add_optional_instance_extension_names(pg, available_extensions,
|
add_optional_instance_extension_names(pg, available_extensions,
|
||||||
enabled_extension_names);
|
enabled_extension_names);
|
||||||
|
|
||||||
fprintf(stderr, "Enabled instance extensions:\n");
|
fprintf(stderr, "Enabled instance extensions:\n");
|
||||||
for (int i = 0; i < enabled_extension_names->len; i++) {
|
for (int i = 0; i < enabled_extension_names->len; i++) {
|
||||||
fprintf(stderr, "- %s\n", g_array_index(enabled_extension_names, char *, i));
|
fprintf(stderr, "- %s\n",
|
||||||
|
g_array_index(enabled_extension_names, char *, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
VkInstanceCreateInfo create_info = {
|
VkInstanceCreateInfo create_info = {
|
||||||
|
@ -270,7 +288,8 @@ static void create_instance(PGRAPHState *pg)
|
||||||
|
|
||||||
if (enable_validation) {
|
if (enable_validation) {
|
||||||
if (check_validation_layer_support()) {
|
if (check_validation_layer_support()) {
|
||||||
fprintf(stderr, "Warning: Validation layers enabled. Expect performance impact.\n");
|
fprintf(stderr, "Warning: Validation layers enabled. Expect "
|
||||||
|
"performance impact.\n");
|
||||||
create_info.enabledLayerCount = ARRAY_SIZE(validation_layers);
|
create_info.enabledLayerCount = ARRAY_SIZE(validation_layers);
|
||||||
create_info.ppEnabledLayerNames = validation_layers;
|
create_info.ppEnabledLayerNames = validation_layers;
|
||||||
if (r->debug_utils_extension_enabled) {
|
if (r->debug_utils_extension_enabled) {
|
||||||
|
@ -283,9 +302,19 @@ static void create_instance(PGRAPHState *pg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VK_CHECK(vkCreateInstance(&create_info, NULL, &r->instance));
|
result = vkCreateInstance(&create_info, NULL, &r->instance);
|
||||||
|
if (result != VK_SUCCESS) {
|
||||||
|
error_setg(errp, "Failed to create instance");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
volkLoadInstance(r->instance);
|
volkLoadInstance(r->instance);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
error:
|
||||||
|
volkFinalize();
|
||||||
|
destroy_window(r);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_queue_family_indicies_complete(QueueFamilyIndices indices)
|
static bool is_queue_family_indicies_complete(QueueFamilyIndices indices)
|
||||||
|
@ -399,15 +428,18 @@ static bool is_device_compatible(VkPhysicalDevice device)
|
||||||
// FIXME: Check vram
|
// FIXME: Check vram
|
||||||
}
|
}
|
||||||
|
|
||||||
static void select_physical_device(PGRAPHState *pg)
|
static bool select_physical_device(PGRAPHState *pg, Error **errp)
|
||||||
{
|
{
|
||||||
PGRAPHVkState *r = pg->vk_renderer_state;
|
PGRAPHVkState *r = pg->vk_renderer_state;
|
||||||
|
VkResult result;
|
||||||
|
|
||||||
uint32_t num_physical_devices = 0;
|
uint32_t num_physical_devices = 0;
|
||||||
|
|
||||||
vkEnumeratePhysicalDevices(r->instance, &num_physical_devices, NULL);
|
result =
|
||||||
if (num_physical_devices == 0) {
|
vkEnumeratePhysicalDevices(r->instance, &num_physical_devices, NULL);
|
||||||
assert(!"failed to find GPUs with Vulkan support");
|
if (result != VK_SUCCESS || num_physical_devices == 0) {
|
||||||
|
error_setg(errp, "Failed to find GPUs with Vulkan support");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_autofree VkPhysicalDevice *devices =
|
g_autofree VkPhysicalDevice *devices =
|
||||||
|
@ -430,7 +462,8 @@ static void select_physical_device(PGRAPHState *pg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (r->physical_device == VK_NULL_HANDLE) {
|
if (r->physical_device == VK_NULL_HANDLE) {
|
||||||
assert(!"failed to find a suitable GPU");
|
error_setg(errp, "Failed to find a suitable GPU");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
vkGetPhysicalDeviceProperties(r->physical_device, &r->device_props);
|
vkGetPhysicalDeviceProperties(r->physical_device, &r->device_props);
|
||||||
|
@ -448,11 +481,13 @@ static void select_physical_device(PGRAPHState *pg)
|
||||||
size_t vsh_attr_values_size =
|
size_t vsh_attr_values_size =
|
||||||
NV2A_VERTEXSHADER_ATTRIBUTES * 4 * sizeof(float);
|
NV2A_VERTEXSHADER_ATTRIBUTES * 4 * sizeof(float);
|
||||||
assert(r->device_props.limits.maxPushConstantsSize >= vsh_attr_values_size);
|
assert(r->device_props.limits.maxPushConstantsSize >= vsh_attr_values_size);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void create_logical_device(PGRAPHState *pg)
|
static bool create_logical_device(PGRAPHState *pg, Error **errp)
|
||||||
{
|
{
|
||||||
PGRAPHVkState *r = pg->vk_renderer_state;
|
PGRAPHVkState *r = pg->vk_renderer_state;
|
||||||
|
VkResult result;
|
||||||
|
|
||||||
QueueFamilyIndices indices =
|
QueueFamilyIndices indices =
|
||||||
pgraph_vk_find_queue_families(r->physical_device);
|
pgraph_vk_find_queue_families(r->physical_device);
|
||||||
|
@ -468,7 +503,8 @@ static void create_logical_device(PGRAPHState *pg)
|
||||||
|
|
||||||
fprintf(stderr, "Enabled device extensions:\n");
|
fprintf(stderr, "Enabled device extensions:\n");
|
||||||
for (int i = 0; i < enabled_extension_names->len; i++) {
|
for (int i = 0; i < enabled_extension_names->len; i++) {
|
||||||
fprintf(stderr, "- %s\n", g_array_index(enabled_extension_names, char *, i));
|
fprintf(stderr, "- %s\n",
|
||||||
|
g_array_index(enabled_extension_names, char *, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
float queuePriority = 1.0f;
|
float queuePriority = 1.0f;
|
||||||
|
@ -501,12 +537,18 @@ static void create_logical_device(PGRAPHState *pg)
|
||||||
bool all_features_available = true;
|
bool all_features_available = true;
|
||||||
for (int i = 0; i < ARRAY_SIZE(required_features); i++) {
|
for (int i = 0; i < ARRAY_SIZE(required_features); i++) {
|
||||||
if (required_features[i].available != VK_TRUE) {
|
if (required_features[i].available != VK_TRUE) {
|
||||||
fprintf(stderr, "Error: Device does not support required feature %s\n", required_features[i].name);
|
fprintf(stderr,
|
||||||
|
"Error: Device does not support required feature %s\n",
|
||||||
|
required_features[i].name);
|
||||||
all_features_available = false;
|
all_features_available = false;
|
||||||
}
|
}
|
||||||
*required_features[i].enabled = VK_TRUE;
|
*required_features[i].enabled = VK_TRUE;
|
||||||
}
|
}
|
||||||
assert(all_features_available);
|
|
||||||
|
if (!all_features_available) {
|
||||||
|
error_setg(errp, "Device does not support required features");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void *next_struct = NULL;
|
void *next_struct = NULL;
|
||||||
|
|
||||||
|
@ -548,10 +590,15 @@ static void create_logical_device(PGRAPHState *pg)
|
||||||
device_create_info.ppEnabledLayerNames = validation_layers;
|
device_create_info.ppEnabledLayerNames = validation_layers;
|
||||||
}
|
}
|
||||||
|
|
||||||
VK_CHECK(vkCreateDevice(r->physical_device, &device_create_info, NULL,
|
result = vkCreateDevice(r->physical_device, &device_create_info, NULL,
|
||||||
&r->device));
|
&r->device);
|
||||||
|
if (result != VK_SUCCESS) {
|
||||||
|
error_setg(errp, "Failed to create logical device");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
vkGetDeviceQueue(r->device, indices.queue_family, 0, &r->queue);
|
vkGetDeviceQueue(r->device, indices.queue_family, 0, &r->queue);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t pgraph_vk_get_memory_type(PGRAPHState *pg, uint32_t type_bits,
|
uint32_t pgraph_vk_get_memory_type(PGRAPHState *pg, uint32_t type_bits,
|
||||||
|
@ -570,9 +617,10 @@ uint32_t pgraph_vk_get_memory_type(PGRAPHState *pg, uint32_t type_bits,
|
||||||
return 0xFFFFFFFF; // Unable to find memoryType
|
return 0xFFFFFFFF; // Unable to find memoryType
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_allocator(PGRAPHState *pg)
|
static bool init_allocator(PGRAPHState *pg, Error **errp)
|
||||||
{
|
{
|
||||||
PGRAPHVkState *r = pg->vk_renderer_state;
|
PGRAPHVkState *r = pg->vk_renderer_state;
|
||||||
|
VkResult result;
|
||||||
|
|
||||||
VmaVulkanFunctions vulkanFunctions = {
|
VmaVulkanFunctions vulkanFunctions = {
|
||||||
/// Required when using VMA_DYNAMIC_VULKAN_FUNCTIONS.
|
/// Required when using VMA_DYNAMIC_VULKAN_FUNCTIONS.
|
||||||
|
@ -631,32 +679,49 @@ static void init_allocator(PGRAPHState *pg)
|
||||||
.pVulkanFunctions = &vulkanFunctions,
|
.pVulkanFunctions = &vulkanFunctions,
|
||||||
};
|
};
|
||||||
|
|
||||||
VK_CHECK(vmaCreateAllocator(&create_info, &r->allocator));
|
result = vmaCreateAllocator(&create_info, &r->allocator);
|
||||||
|
if (result != VK_SUCCESS) {
|
||||||
|
error_setg(errp, "vmaCreateAllocator failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void finalize_allocator(PGRAPHState *pg)
|
void pgraph_vk_init_instance(PGRAPHState *pg, Error **errp)
|
||||||
{
|
{
|
||||||
PGRAPHVkState *r = pg->vk_renderer_state;
|
if (create_instance(pg, errp) &&
|
||||||
|
select_physical_device(pg, errp) &&
|
||||||
|
create_logical_device(pg, errp) &&
|
||||||
|
init_allocator(pg, errp)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
vmaDestroyAllocator(r->allocator);
|
if (*errp) {
|
||||||
}
|
error_prepend(errp, "Failed to initialize Vulkan renderer: ");
|
||||||
|
}
|
||||||
void pgraph_vk_init_instance(PGRAPHState *pg)
|
pgraph_vk_finalize_instance(pg);
|
||||||
{
|
|
||||||
create_instance(pg);
|
|
||||||
select_physical_device(pg);
|
|
||||||
create_logical_device(pg);
|
|
||||||
init_allocator(pg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pgraph_vk_finalize_instance(PGRAPHState *pg)
|
void pgraph_vk_finalize_instance(PGRAPHState *pg)
|
||||||
{
|
{
|
||||||
PGRAPHVkState *r = pg->vk_renderer_state;
|
PGRAPHVkState *r = pg->vk_renderer_state;
|
||||||
|
|
||||||
finalize_allocator(pg);
|
if (r->allocator != VK_NULL_HANDLE) {
|
||||||
vkDestroyDevice(r->device, NULL);
|
vmaDestroyAllocator(r->allocator);
|
||||||
r->device = VK_NULL_HANDLE;
|
r->allocator = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
vkDestroyInstance(r->instance, NULL);
|
if (r->device != VK_NULL_HANDLE) {
|
||||||
r->instance = VK_NULL_HANDLE;
|
vkDestroyDevice(r->device, NULL);
|
||||||
|
r->device = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r->instance != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyInstance(r->instance, NULL);
|
||||||
|
r->instance = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
volkFinalize();
|
||||||
|
destroy_window(r);
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ static void early_context_init(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pgraph_vk_init(NV2AState *d)
|
static void pgraph_vk_init(NV2AState *d, Error **errp)
|
||||||
{
|
{
|
||||||
PGRAPHState *pg = &d->pgraph;
|
PGRAPHState *pg = &d->pgraph;
|
||||||
|
|
||||||
|
@ -45,7 +45,11 @@ static void pgraph_vk_init(NV2AState *d)
|
||||||
|
|
||||||
pgraph_vk_debug_init();
|
pgraph_vk_debug_init();
|
||||||
|
|
||||||
pgraph_vk_init_instance(pg);
|
pgraph_vk_init_instance(pg, errp);
|
||||||
|
if (*errp) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
pgraph_vk_init_command_buffers(pg);
|
pgraph_vk_init_command_buffers(pg);
|
||||||
pgraph_vk_init_buffers(d);
|
pgraph_vk_init_buffers(d);
|
||||||
pgraph_vk_init_surfaces(pg);
|
pgraph_vk_init_surfaces(pg);
|
||||||
|
|
|
@ -380,7 +380,7 @@ void pgraph_vk_check_memory_budget(PGRAPHState *pg);
|
||||||
void pgraph_vk_debug_init(void);
|
void pgraph_vk_debug_init(void);
|
||||||
|
|
||||||
// instance.c
|
// instance.c
|
||||||
void pgraph_vk_init_instance(PGRAPHState *pg);
|
void pgraph_vk_init_instance(PGRAPHState *pg, Error **errp);
|
||||||
void pgraph_vk_finalize_instance(PGRAPHState *pg);
|
void pgraph_vk_finalize_instance(PGRAPHState *pg);
|
||||||
QueueFamilyIndices pgraph_vk_find_queue_families(VkPhysicalDevice device);
|
QueueFamilyIndices pgraph_vk_find_queue_families(VkPhysicalDevice device);
|
||||||
uint32_t pgraph_vk_get_memory_type(PGRAPHState *pg, uint32_t type_bits,
|
uint32_t pgraph_vk_get_memory_type(PGRAPHState *pg, uint32_t type_bits,
|
||||||
|
|
Loading…
Reference in New Issue