mirror of https://github.com/xemu-project/xemu.git
205 lines
6.3 KiB
C
205 lines
6.3 KiB
C
/*
|
|
* Geforce NV2A PGRAPH OpenGL Renderer
|
|
*
|
|
* Copyright (c) 2012 espes
|
|
* Copyright (c) 2015 Jannik Vogel
|
|
* Copyright (c) 2018-2025 Matt Borgerson
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "hw/xbox/nv2a/nv2a_int.h"
|
|
#include "hw/xbox/nv2a/pgraph/pgraph.h"
|
|
#include "debug.h"
|
|
#include "renderer.h"
|
|
|
|
GloContext *g_nv2a_context_render;
|
|
GloContext *g_nv2a_context_display;
|
|
|
|
static void early_context_init(void)
|
|
{
|
|
g_nv2a_context_render = glo_context_create();
|
|
g_nv2a_context_display = glo_context_create();
|
|
}
|
|
|
|
static void pgraph_gl_init(NV2AState *d, Error **errp)
|
|
{
|
|
PGRAPHState *pg = &d->pgraph;
|
|
|
|
pg->gl_renderer_state = g_malloc0(sizeof(*pg->gl_renderer_state));
|
|
PGRAPHGLState *r = pg->gl_renderer_state;
|
|
|
|
/* fire up opengl */
|
|
glo_set_current(g_nv2a_context_render);
|
|
|
|
#if 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"));
|
|
|
|
glGetFloatv(GL_SMOOTH_LINE_WIDTH_RANGE, r->supported_smooth_line_width_range);
|
|
glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, r->supported_aliased_line_width_range);
|
|
|
|
pgraph_gl_init_surfaces(pg);
|
|
pgraph_gl_init_reports(d);
|
|
pgraph_gl_init_textures(d);
|
|
pgraph_gl_init_buffers(d);
|
|
pgraph_gl_init_shaders(pg);
|
|
pgraph_gl_init_display(d);
|
|
|
|
pgraph_gl_update_entire_memory_buffer(d);
|
|
|
|
pg->uniform_attrs = 0;
|
|
pg->swizzle_attrs = 0;
|
|
}
|
|
|
|
static void pgraph_gl_finalize(NV2AState *d)
|
|
{
|
|
PGRAPHState *pg = &d->pgraph;
|
|
|
|
glo_set_current(g_nv2a_context_render);
|
|
|
|
pgraph_gl_finalize_surfaces(pg);
|
|
pgraph_gl_finalize_shaders(pg);
|
|
pgraph_gl_finalize_textures(pg);
|
|
pgraph_gl_finalize_reports(pg);
|
|
pgraph_gl_finalize_buffers(pg);
|
|
pgraph_gl_finalize_display(pg);
|
|
|
|
glo_set_current(NULL);
|
|
|
|
g_free(pg->gl_renderer_state);
|
|
pg->gl_renderer_state = NULL;
|
|
}
|
|
|
|
static void pgraph_gl_flip_stall(NV2AState *d)
|
|
{
|
|
NV2A_GL_DFRAME_TERMINATOR();
|
|
glFinish();
|
|
}
|
|
|
|
static void pgraph_gl_flush(NV2AState *d)
|
|
{
|
|
pgraph_gl_surface_flush(d);
|
|
pgraph_gl_mark_textures_possibly_dirty(d, 0, memory_region_size(d->vram));
|
|
pgraph_gl_update_entire_memory_buffer(d);
|
|
/* FIXME: Flush more? */
|
|
|
|
qatomic_set(&d->pgraph.flush_pending, false);
|
|
qemu_event_set(&d->pgraph.flush_complete);
|
|
}
|
|
|
|
static void pgraph_gl_process_pending(NV2AState *d)
|
|
{
|
|
PGRAPHState *pg = &d->pgraph;
|
|
PGRAPHGLState *r = pg->gl_renderer_state;
|
|
|
|
if (qatomic_read(&r->downloads_pending) ||
|
|
qatomic_read(&r->download_dirty_surfaces_pending) ||
|
|
qatomic_read(&d->pgraph.sync_pending) ||
|
|
qatomic_read(&d->pgraph.flush_pending) ||
|
|
qatomic_read(&r->shader_cache_writeback_pending)) {
|
|
qemu_mutex_unlock(&d->pfifo.lock);
|
|
qemu_mutex_lock(&d->pgraph.lock);
|
|
if (qatomic_read(&r->downloads_pending)) {
|
|
pgraph_gl_process_pending_downloads(d);
|
|
}
|
|
if (qatomic_read(&r->download_dirty_surfaces_pending)) {
|
|
pgraph_gl_download_dirty_surfaces(d);
|
|
}
|
|
if (qatomic_read(&d->pgraph.sync_pending)) {
|
|
pgraph_gl_sync(d);
|
|
}
|
|
if (qatomic_read(&d->pgraph.flush_pending)) {
|
|
pgraph_gl_flush(d);
|
|
}
|
|
if (qatomic_read(&r->shader_cache_writeback_pending)) {
|
|
pgraph_gl_shader_write_cache_reload_list(&d->pgraph);
|
|
}
|
|
qemu_mutex_unlock(&d->pgraph.lock);
|
|
qemu_mutex_lock(&d->pfifo.lock);
|
|
}
|
|
}
|
|
|
|
static void pgraph_gl_pre_savevm_trigger(NV2AState *d)
|
|
{
|
|
PGRAPHState *pg = &d->pgraph;
|
|
PGRAPHGLState *r = pg->gl_renderer_state;
|
|
|
|
qatomic_set(&r->download_dirty_surfaces_pending, true);
|
|
qemu_event_reset(&r->dirty_surfaces_download_complete);
|
|
}
|
|
|
|
static void pgraph_gl_pre_savevm_wait(NV2AState *d)
|
|
{
|
|
PGRAPHState *pg = &d->pgraph;
|
|
PGRAPHGLState *r = pg->gl_renderer_state;
|
|
|
|
qemu_event_wait(&r->dirty_surfaces_download_complete);
|
|
}
|
|
|
|
static void pgraph_gl_pre_shutdown_trigger(NV2AState *d)
|
|
{
|
|
PGRAPHState *pg = &d->pgraph;
|
|
PGRAPHGLState *r = pg->gl_renderer_state;
|
|
|
|
qatomic_set(&r->shader_cache_writeback_pending, true);
|
|
qemu_event_reset(&r->shader_cache_writeback_complete);
|
|
}
|
|
|
|
static void pgraph_gl_pre_shutdown_wait(NV2AState *d)
|
|
{
|
|
PGRAPHState *pg = &d->pgraph;
|
|
PGRAPHGLState *r = pg->gl_renderer_state;
|
|
|
|
qemu_event_wait(&r->shader_cache_writeback_complete);
|
|
}
|
|
|
|
static PGRAPHRenderer pgraph_gl_renderer = {
|
|
.type = CONFIG_DISPLAY_RENDERER_OPENGL,
|
|
.name = "OpenGL",
|
|
.ops = {
|
|
.init = pgraph_gl_init,
|
|
.early_context_init = early_context_init,
|
|
.finalize = pgraph_gl_finalize,
|
|
.clear_report_value = pgraph_gl_clear_report_value,
|
|
.clear_surface = pgraph_gl_clear_surface,
|
|
.draw_begin = pgraph_gl_draw_begin,
|
|
.draw_end = pgraph_gl_draw_end,
|
|
.flip_stall = pgraph_gl_flip_stall,
|
|
.flush_draw = pgraph_gl_flush_draw,
|
|
.get_report = pgraph_gl_get_report,
|
|
.image_blit = pgraph_gl_image_blit,
|
|
.pre_savevm_trigger = pgraph_gl_pre_savevm_trigger,
|
|
.pre_savevm_wait = pgraph_gl_pre_savevm_wait,
|
|
.pre_shutdown_trigger = pgraph_gl_pre_shutdown_trigger,
|
|
.pre_shutdown_wait = pgraph_gl_pre_shutdown_wait,
|
|
.process_pending = pgraph_gl_process_pending,
|
|
.process_pending_reports = pgraph_gl_process_pending_reports,
|
|
.surface_update = pgraph_gl_surface_update,
|
|
.set_surface_scale_factor = pgraph_gl_set_surface_scale_factor,
|
|
.get_surface_scale_factor = pgraph_gl_get_surface_scale_factor,
|
|
.get_framebuffer_surface = pgraph_gl_get_framebuffer_surface,
|
|
}
|
|
};
|
|
|
|
static void __attribute__((constructor)) register_renderer(void)
|
|
{
|
|
pgraph_renderer_register(&pgraph_gl_renderer);
|
|
}
|