nv2a/gl: Improve renderer teardown

This commit is contained in:
Matt Borgerson 2024-07-26 17:21:01 -07:00 committed by mborgerson
parent c1eb48b62f
commit 84dd112186
8 changed files with 180 additions and 57 deletions

View File

@ -102,6 +102,33 @@ void pgraph_gl_init_display_renderer(NV2AState *d)
assert(glGetError() == GL_NO_ERROR);
}
void pgraph_gl_finalize_display(PGRAPHState *pg)
{
PGRAPHGLState *r = pg->gl_renderer_state;
glo_set_current(g_nv2a_context_display);
glDeleteTextures(1, &r->gl_display_buffer);
r->gl_display_buffer = 0;
glDeleteProgram(r->disp_rndr.prog);
r->disp_rndr.prog = 0;
glDeleteVertexArrays(1, &r->disp_rndr.vao);
r->disp_rndr.vao = 0;
glDeleteBuffers(1, &r->disp_rndr.vbo);
r->disp_rndr.vbo = 0;
glDeleteFramebuffers(1, &r->disp_rndr.fbo);
r->disp_rndr.fbo = 0;
glDeleteTextures(1, &r->disp_rndr.pvideo_tex);
r->disp_rndr.pvideo_tex = 0;
glo_set_current(g_nv2a_context_render);
}
static uint8_t *convert_texture_data__CR8YB8CB8YA8(const uint8_t *data,
unsigned int width,
unsigned int height,

View File

@ -33,24 +33,63 @@ static void nv2a_gl_context_init(void)
g_nv2a_context_display = glo_context_create();
}
static void pgraph_gl_init(NV2AState *d)
{
PGRAPHState *pg = &d->pgraph;
pg->gl_renderer_state = g_malloc0(sizeof(*pg->gl_renderer_state));
/* fire up opengl */
glo_set_current(g_nv2a_context_render);
#ifdef DEBUG_NV2A_GL
gl_debug_initialize();
#endif
/* DXT textures */
assert(glo_check_extension("GL_EXT_texture_compression_s3tc"));
/* Internal RGB565 texture format */
assert(glo_check_extension("GL_ARB_ES2_compatibility"));
pgraph_gl_init_surfaces(pg);
pgraph_gl_init_reports(d);
pgraph_gl_init_texture_cache(d);
pgraph_gl_init_vertex_cache(d);
pgraph_gl_init_shader_cache(pg);
glo_set_current(g_nv2a_context_display);
pgraph_gl_init_display_renderer(d);
pgraph_gl_update_entire_memory_buffer(d);
glo_set_current(NULL);
pg->uniform_attrs = 0;
pg->swizzle_attrs = 0;
}
static void pgraph_gl_init_thread(NV2AState *d)
{
glo_set_current(g_nv2a_context_render);
}
static void pgraph_gl_deinit(NV2AState *d)
static void pgraph_gl_finalize(NV2AState *d)
{
PGRAPHState *pg = &d->pgraph;
glo_set_current(g_nv2a_context_render);
pgraph_gl_deinit_surfaces(pg);
pgraph_gl_deinit_shader_cache(pg);
pgraph_gl_deinit_texture_cache(pg);
pgraph_gl_finalize_surfaces(pg);
pgraph_gl_finalize_shaders(pg);
pgraph_gl_finalize_textures(pg);
pgraph_gl_finalize_reports(pg);
pgraph_gl_finalize_vertex(pg);
pgraph_gl_finalize_display(pg);
glo_set_current(NULL);
glo_context_destroy(g_nv2a_context_render);
glo_context_destroy(g_nv2a_context_display);
g_free(pg->gl_renderer_state);
pg->gl_renderer_state = NULL;
}
static void pgraph_gl_flip_stall(NV2AState *d)
@ -136,36 +175,6 @@ static void pgraph_gl_pre_shutdown_wait(NV2AState *d)
qemu_event_wait(&r->shader_cache_writeback_complete);
}
static void pgraph_gl_init(NV2AState *d)
{
PGRAPHState *pg = &d->pgraph;
pg->gl_renderer_state = g_malloc(sizeof(PGRAPHGLState));
/* fire up opengl */
glo_set_current(g_nv2a_context_render);
#ifdef DEBUG_NV2A_GL
gl_debug_initialize();
#endif
/* DXT textures */
assert(glo_check_extension("GL_EXT_texture_compression_s3tc"));
/* Internal RGB565 texture format */
assert(glo_check_extension("GL_ARB_ES2_compatibility"));
pgraph_gl_init_surfaces(pg);
pgraph_gl_init_reports(d);
pgraph_gl_init_texture_cache(d);
pgraph_gl_init_vertex_cache(d);
pgraph_gl_init_shader_cache(pg);
glo_set_current(g_nv2a_context_display);
pgraph_gl_init_display_renderer(d);
glo_set_current(NULL);
}
static PGRAPHRenderer pgraph_gl_renderer = {
.type = CONFIG_DISPLAY_RENDERER_OPENGL,
.name = "OpenGL",
@ -173,7 +182,7 @@ static PGRAPHRenderer pgraph_gl_renderer = {
.init = pgraph_gl_init,
.early_context_init = nv2a_gl_context_init,
.init_thread = pgraph_gl_init_thread,
.finalize = pgraph_gl_deinit,
.finalize = pgraph_gl_finalize,
.clear_report_value = pgraph_gl_clear_report_value,
.clear_surface = pgraph_gl_clear_surface,
.draw_begin = pgraph_gl_draw_begin,

View File

@ -240,9 +240,6 @@ void pgraph_gl_bind_textures(NV2AState *d);
void pgraph_gl_bind_vertex_attributes(NV2AState *d, unsigned int min_element, unsigned int max_element, bool inline_data, unsigned int inline_stride, unsigned int provoking_element);
bool pgraph_gl_check_surface_to_texture_compatibility(const SurfaceBinding *surface, const TextureShape *shape);
GLuint pgraph_gl_compile_shader(const char *vs_src, const char *fs_src);
void pgraph_gl_deinit_shader_cache(PGRAPHState *pg);
void pgraph_gl_deinit_surfaces(PGRAPHState *pg);
void pgraph_gl_deinit_texture_cache(PGRAPHState *pg);
void pgraph_gl_download_dirty_surfaces(NV2AState *d);
void pgraph_gl_clear_report_value(NV2AState *d);
void pgraph_gl_clear_surface(NV2AState *d, uint32_t parameter);
@ -258,11 +255,17 @@ void pgraph_gl_surface_update(NV2AState *d, bool upload, bool color_write, bool
void pgraph_gl_sync(NV2AState *d);
void pgraph_gl_update_entire_memory_buffer(NV2AState *d);
void pgraph_gl_init_display_renderer(NV2AState *d);
void pgraph_gl_finalize_display(PGRAPHState *pg);
void pgraph_gl_init_reports(NV2AState *d);
void pgraph_gl_finalize_reports(PGRAPHState *pg);
void pgraph_gl_init_shader_cache(PGRAPHState *pg);
void pgraph_gl_finalize_shaders(PGRAPHState *pg);
void pgraph_gl_init_surfaces(PGRAPHState *pg);
void pgraph_gl_finalize_surfaces(PGRAPHState *pg);
void pgraph_gl_init_texture_cache(NV2AState *d);
void pgraph_gl_finalize_textures(PGRAPHState *pg);
void pgraph_gl_init_vertex_cache(NV2AState *d);
void pgraph_gl_finalize_vertex(PGRAPHState *pg);
void pgraph_gl_process_pending_downloads(NV2AState *d);
void pgraph_gl_reload_surface_scale_factor(PGRAPHState *pg);
void pgraph_gl_render_surface_to_texture(NV2AState *d, SurfaceBinding *surface, TextureBinding *texture, TextureShape *texture_shape, int texture_unit);

View File

@ -109,3 +109,23 @@ void pgraph_gl_get_report(NV2AState *d, uint32_t parameter)
r->gl_zpass_pixel_count_query_count = 0;
r->gl_zpass_pixel_count_queries = NULL;
}
void pgraph_gl_finalize_reports(PGRAPHState *pg)
{
PGRAPHGLState *r = pg->gl_renderer_state;
QueryReport *report, *next;
QSIMPLEQ_FOREACH_SAFE (report, &r->report_queue, entry, next) {
if (report->query_count) {
glDeleteQueries(report->query_count, report->queries);
}
QSIMPLEQ_REMOVE_HEAD(&r->report_queue, entry);
g_free(report);
}
if (r->gl_zpass_pixel_count_query_count) {
glDeleteQueries(r->gl_zpass_pixel_count_query_count,
r->gl_zpass_pixel_count_queries);
r->gl_zpass_pixel_count_query_count = 0;
}
}

View File

@ -581,13 +581,15 @@ void pgraph_gl_init_shader_cache(PGRAPHState *pg)
shader_reload_lru_from_disk, pg, QEMU_THREAD_JOINABLE);
}
void pgraph_gl_deinit_shader_cache(PGRAPHState *pg)
void pgraph_gl_finalize_shaders(PGRAPHState *pg)
{
PGRAPHGLState *r = pg->gl_renderer_state;
// Clear out shader cache
pgraph_gl_shader_write_cache_reload_list(pg);
pgraph_gl_shader_write_cache_reload_list(pg); // FIXME: also flushes, rename for clarity
free(r->shader_cache_entries);
r->shader_cache_entries = NULL;
qemu_mutex_destroy(&r->shader_cache_lock);
}

View File

@ -162,6 +162,23 @@ static void init_render_to_texture(PGRAPHState *pg)
glGenFramebuffers(1, &r->s2t_rndr.fbo);
}
static void finalize_render_to_texture(PGRAPHState *pg)
{
PGRAPHGLState *r = pg->gl_renderer_state;
glDeleteProgram(r->s2t_rndr.prog);
r->s2t_rndr.prog = 0;
glDeleteVertexArrays(1, &r->s2t_rndr.vao);
r->s2t_rndr.vao = 0;
glDeleteBuffers(1, &r->s2t_rndr.vbo);
r->s2t_rndr.vbo = 0;
glDeleteFramebuffers(1, &r->s2t_rndr.fbo);
r->s2t_rndr.fbo = 0;
}
static bool surface_to_texture_can_fastpath(SurfaceBinding *surface,
TextureShape *shape)
{
@ -1365,21 +1382,11 @@ void pgraph_gl_init_surfaces(PGRAPHState *pg)
init_render_to_texture(pg);
}
void pgraph_gl_deinit_surfaces(PGRAPHState *pg)
{
PGRAPHGLState *r = pg->gl_renderer_state;
glDeleteFramebuffers(1, &r->gl_framebuffer);
// TODO: clear out surfaces
}
void pgraph_gl_surface_flush(NV2AState *d)
static void flush_surfaces(NV2AState *d)
{
PGRAPHState *pg = &d->pgraph;
PGRAPHGLState *r = pg->gl_renderer_state;
bool update_surface = (r->color_binding || r->zeta_binding);
/* Clear last surface shape to force recreation of buffers at next draw */
pg->surface_color.draw_dirty = false;
pg->surface_zeta.draw_dirty = false;
@ -1391,6 +1398,28 @@ void pgraph_gl_surface_flush(NV2AState *d)
QTAILQ_FOREACH_SAFE(s, &r->surfaces, entry, next) {
pgraph_gl_surface_invalidate(d, s);
}
}
void pgraph_gl_finalize_surfaces(PGRAPHState *pg)
{
NV2AState *d = container_of(pg, NV2AState, pgraph);
PGRAPHGLState *r = pg->gl_renderer_state;
flush_surfaces(d);
glDeleteFramebuffers(1, &r->gl_framebuffer);
r->gl_framebuffer = 0;
finalize_render_to_texture(pg);
}
void pgraph_gl_surface_flush(NV2AState *d)
{
PGRAPHState *pg = &d->pgraph;
PGRAPHGLState *r = pg->gl_renderer_state;
bool update_surface = (r->color_binding || r->zeta_binding);
flush_surfaces(d);
pgraph_gl_reload_surface_scale_factor(pg);

View File

@ -809,11 +809,16 @@ void pgraph_gl_init_texture_cache(NV2AState *d)
r->texture_cache.post_node_evict = texture_cache_entry_post_evict;
}
void pgraph_gl_deinit_texture_cache(PGRAPHState *pg)
void pgraph_gl_finalize_textures(PGRAPHState *pg)
{
PGRAPHGLState *r = pg->gl_renderer_state;
// Clear out texture cache
for (int i = 0; i < NV2A_MAX_TEXTURES; i++) {
r->texture_binding[i] = NULL;
}
lru_flush(&r->texture_cache);
free(r->texture_cache_entries);
r->texture_cache_entries = NULL;
}

View File

@ -245,14 +245,15 @@ static bool vertex_cache_entry_compare(Lru *lru, LruNode *node, void *key)
return memcmp(&vnode->key, key, sizeof(VertexKey));
}
static const size_t element_cache_size = 50*1024;
void pgraph_gl_init_vertex_cache(NV2AState *d)
{
PGRAPHState *pg = &d->pgraph;
PGRAPHGLState *r = pg->gl_renderer_state;
const size_t element_cache_size = 50*1024;
lru_init(&r->element_cache);
r->element_cache_entries = malloc(element_cache_size * sizeof(VertexLruNode));
r->element_cache_entries = g_malloc_n(element_cache_size, sizeof(VertexLruNode));
assert(r->element_cache_entries != NULL);
GLuint element_cache_buffers[element_cache_size];
glGenBuffers(element_cache_size, element_cache_buffers);
@ -281,3 +282,30 @@ void pgraph_gl_init_vertex_cache(NV2AState *d)
assert(glGetError() == GL_NO_ERROR);
}
void pgraph_gl_finalize_vertex(PGRAPHState *pg)
{
PGRAPHGLState *r = pg->gl_renderer_state;
GLuint element_cache_buffers[element_cache_size];
for (int i = 0; i < element_cache_size; i++) {
element_cache_buffers[i] = r->element_cache_entries[i].gl_buffer;
}
glDeleteBuffers(element_cache_size, element_cache_buffers);
lru_flush(&r->element_cache);
g_free(r->element_cache_entries);
r->element_cache_entries = NULL;
glDeleteBuffers(NV2A_VERTEXSHADER_ATTRIBUTES, r->gl_inline_buffer);
memset(r->gl_inline_buffer, 0, sizeof(r->gl_inline_buffer));
glDeleteBuffers(1, &r->gl_inline_array_buffer);
r->gl_inline_array_buffer = 0;
glDeleteBuffers(1, &r->gl_memory_buffer);
r->gl_memory_buffer = 0;
glDeleteVertexArrays(1, &r->gl_vertex_array);
r->gl_vertex_array = 0;
}