diff --git a/hw/xbox/nv2a/pgraph/gl/display.c b/hw/xbox/nv2a/pgraph/gl/display.c index 804fec2c2d..ed0992e883 100644 --- a/hw/xbox/nv2a/pgraph/gl/display.c +++ b/hw/xbox/nv2a/pgraph/gl/display.c @@ -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, diff --git a/hw/xbox/nv2a/pgraph/gl/renderer.c b/hw/xbox/nv2a/pgraph/gl/renderer.c index 2114608683..930e4454c1 100644 --- a/hw/xbox/nv2a/pgraph/gl/renderer.c +++ b/hw/xbox/nv2a/pgraph/gl/renderer.c @@ -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, diff --git a/hw/xbox/nv2a/pgraph/gl/renderer.h b/hw/xbox/nv2a/pgraph/gl/renderer.h index fff4ac7d53..5044f9d5a2 100644 --- a/hw/xbox/nv2a/pgraph/gl/renderer.h +++ b/hw/xbox/nv2a/pgraph/gl/renderer.h @@ -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); diff --git a/hw/xbox/nv2a/pgraph/gl/reports.c b/hw/xbox/nv2a/pgraph/gl/reports.c index 0673c37e0c..2dea09e590 100644 --- a/hw/xbox/nv2a/pgraph/gl/reports.c +++ b/hw/xbox/nv2a/pgraph/gl/reports.c @@ -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; + } +} diff --git a/hw/xbox/nv2a/pgraph/gl/shaders.c b/hw/xbox/nv2a/pgraph/gl/shaders.c index 0bb4eaa598..ab3928afd7 100644 --- a/hw/xbox/nv2a/pgraph/gl/shaders.c +++ b/hw/xbox/nv2a/pgraph/gl/shaders.c @@ -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); } diff --git a/hw/xbox/nv2a/pgraph/gl/surface.c b/hw/xbox/nv2a/pgraph/gl/surface.c index 332ca7199e..a2a00d09ac 100644 --- a/hw/xbox/nv2a/pgraph/gl/surface.c +++ b/hw/xbox/nv2a/pgraph/gl/surface.c @@ -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); diff --git a/hw/xbox/nv2a/pgraph/gl/texture.c b/hw/xbox/nv2a/pgraph/gl/texture.c index bf072f44d6..942d1fe194 100644 --- a/hw/xbox/nv2a/pgraph/gl/texture.c +++ b/hw/xbox/nv2a/pgraph/gl/texture.c @@ -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; } diff --git a/hw/xbox/nv2a/pgraph/gl/vertex.c b/hw/xbox/nv2a/pgraph/gl/vertex.c index 21f42b647c..2fd39db7c6 100644 --- a/hw/xbox/nv2a/pgraph/gl/vertex.c +++ b/hw/xbox/nv2a/pgraph/gl/vertex.c @@ -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; +} \ No newline at end of file