This commit is contained in:
Hugo Locurcio 2025-04-17 10:55:08 +02:00 committed by GitHub
commit c69179d64b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 176 additions and 9 deletions

View File

@ -146,6 +146,9 @@ display:
surface_scale:
type: integer
default: 1
anisotropic_filter_level:
type: integer
default: 1
window:
fullscreen_on_startup: bool
fullscreen_exclusive: bool

View File

@ -27,6 +27,8 @@ int nv2a_get_framebuffer_surface(void);
void nv2a_release_framebuffer_surface(void);
void nv2a_set_surface_scale_factor(unsigned int scale);
unsigned int nv2a_get_surface_scale_factor(void);
void nv2a_set_anisotropic_filter_level(unsigned int level_po2);
unsigned int nv2a_get_anisotropic_filter_level(void);
const uint8_t *nv2a_get_dac_palette(void);
int nv2a_get_screen_off(void);

View File

@ -194,6 +194,8 @@ static PGRAPHRenderer pgraph_gl_renderer = {
.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,
.set_anisotropic_filter_level = pgraph_gl_set_anisotropic_filter_level,
.get_anisotropic_filter_level = pgraph_gl_get_anisotropic_filter_level,
.get_framebuffer_surface = pgraph_gl_get_framebuffer_surface,
}
};

View File

@ -285,6 +285,9 @@ bool pgraph_gl_shader_load_from_memory(ShaderBinding *snode);
void pgraph_gl_shader_write_cache_reload_list(PGRAPHState *pg);
void pgraph_gl_set_surface_scale_factor(NV2AState *d, unsigned int scale);
unsigned int pgraph_gl_get_surface_scale_factor(NV2AState *d);
void pgraph_gl_set_anisotropic_filter_level(NV2AState *d, unsigned int level_po2);
unsigned int pgraph_gl_get_anisotropic_filter_level(NV2AState *d);
void pgraph_gl_reload_anisotropic_filter_level(PGRAPHState *pg);
int pgraph_gl_get_framebuffer_surface(NV2AState *d);
#endif

View File

@ -24,6 +24,7 @@
#include "hw/xbox/nv2a/pgraph/swizzle.h"
#include "hw/xbox/nv2a/pgraph/s3tc.h"
#include "hw/xbox/nv2a/pgraph/texture.h"
#include "ui/xemu-settings.h"
#include "debug.h"
#include "renderer.h"
@ -112,6 +113,7 @@ static void apply_texture_parameters(TextureBinding *binding,
unsigned int dimensionality,
unsigned int filter,
unsigned int address,
unsigned int anisotropic_filter_level,
bool is_bordered,
uint32_t border_color)
{
@ -174,6 +176,8 @@ static void apply_texture_parameters(TextureBinding *binding,
needs_border_color = needs_border_color || binding->addrp == NV_PGRAPH_TEXADDRESS0_ADDRU_BORDER;
}
glTexParameterf(binding->gl_target, GL_TEXTURE_MAX_ANISOTROPY, 1 << anisotropic_filter_level);
if (!is_bordered && needs_border_color) {
if (!binding->border_color_set || binding->border_color != border_color) {
/* FIXME: Color channels might be wrong order */
@ -260,6 +264,7 @@ void pgraph_gl_bind_textures(NV2AState *d)
state.dimensionality,
filter,
address,
pg->anisotropic_filter_level,
state.border,
border_color);
continue;
@ -370,6 +375,7 @@ void pgraph_gl_bind_textures(NV2AState *d)
state.dimensionality,
filter,
address,
pg->anisotropic_filter_level,
state.border,
border_color);
@ -771,6 +777,53 @@ static bool texture_cache_entry_compare(Lru *lru, LruNode *node, void *key)
return memcmp(&tnode->key, key, sizeof(TextureKey));
}
void pgraph_gl_set_anisotropic_filter_level(NV2AState *d, unsigned int level_po2)
{
PGRAPHState *pg = &d->pgraph;
PGRAPHGLState *r = pg->gl_renderer_state;
g_config.display.quality.anisotropic_filter_level = level_po2;
qemu_mutex_lock(&d->pfifo.lock);
qatomic_set(&d->pfifo.halt, true);
qemu_mutex_unlock(&d->pfifo.lock);
qemu_mutex_lock(&d->pgraph.lock);
qemu_event_reset(&r->dirty_surfaces_download_complete);
qatomic_set(&r->download_dirty_surfaces_pending, true);
qemu_mutex_unlock(&d->pgraph.lock);
qemu_mutex_lock(&d->pfifo.lock);
pfifo_kick(d);
qemu_mutex_unlock(&d->pfifo.lock);
qemu_event_wait(&r->dirty_surfaces_download_complete);
qemu_mutex_lock(&d->pgraph.lock);
qemu_event_reset(&d->pgraph.flush_complete);
qatomic_set(&d->pgraph.flush_pending, true);
qemu_mutex_unlock(&d->pgraph.lock);
qemu_mutex_lock(&d->pfifo.lock);
pfifo_kick(d);
qemu_mutex_unlock(&d->pfifo.lock);
qemu_event_wait(&d->pgraph.flush_complete);
qemu_mutex_lock(&d->pfifo.lock);
qatomic_set(&d->pfifo.halt, false);
pfifo_kick(d);
qemu_mutex_unlock(&d->pfifo.lock);
pgraph_gl_reload_anisotropic_filter_level(&d->pgraph);
}
unsigned int pgraph_gl_get_anisotropic_filter_level(NV2AState *d)
{
return d->pgraph.anisotropic_filter_level;
}
void pgraph_gl_reload_anisotropic_filter_level(PGRAPHState *pg)
{
pg->anisotropic_filter_level = g_config.display.quality.anisotropic_filter_level;
}
void pgraph_gl_init_textures(NV2AState *d)
{
PGRAPHState *pg = &d->pgraph;

View File

@ -408,6 +408,35 @@ unsigned int nv2a_get_surface_scale_factor(void)
return s;
}
void nv2a_set_anisotropic_filter_level(unsigned int level_po2)
{
NV2AState *d = g_nv2a;
bql_unlock();
qemu_mutex_lock(&d->pgraph.renderer_lock);
if (d->pgraph.renderer->ops.set_anisotropic_filter_level) {
d->pgraph.renderer->ops.set_anisotropic_filter_level(d, level_po2);
}
qemu_mutex_unlock(&d->pgraph.renderer_lock);
bql_lock();
}
unsigned int nv2a_get_anisotropic_filter_level(void)
{
NV2AState *d = g_nv2a;
int s = 1;
bql_unlock();
qemu_mutex_lock(&d->pgraph.renderer_lock);
if (d->pgraph.renderer->ops.get_anisotropic_filter_level) {
s = d->pgraph.renderer->ops.get_anisotropic_filter_level(d);
}
qemu_mutex_unlock(&d->pgraph.renderer_lock);
bql_lock();
return s;
}
#define METHOD_ADDR(gclass, name) \
gclass ## _ ## name
#define METHOD_ADDR_TO_INDEX(x) ((x)>>2)

View File

@ -120,6 +120,8 @@ typedef struct PGRAPHRenderer {
void (*surface_update)(NV2AState *d, bool upload, bool color_write, bool zeta_write);
void (*set_surface_scale_factor)(NV2AState *d, unsigned int scale);
unsigned int (*get_surface_scale_factor)(NV2AState *d);
void (*set_anisotropic_filter_level)(NV2AState *d, unsigned int level_po2);
unsigned int (*get_anisotropic_filter_level)(NV2AState *d);
int (*get_framebuffer_surface)(NV2AState *d);
} ops;
} PGRAPHRenderer;
@ -246,6 +248,9 @@ typedef struct PGRAPHState {
unsigned int surface_scale_factor;
uint8_t *scale_buf;
// Defined as a power of 2
unsigned int anisotropic_filter_level;
const PGRAPHRenderer *renderer;
union {
PGRAPHNullState *null_renderer_state;

View File

@ -164,7 +164,7 @@ static void pgraph_vk_pre_shutdown_trigger(NV2AState *d)
static void pgraph_vk_pre_shutdown_wait(NV2AState *d)
{
// qemu_event_wait(&d->pgraph.vk_renderer_state->shader_cache_writeback_complete);
// qemu_event_wait(&d->pgraph.vk_renderer_state->shader_cache_writeback_complete);
}
static int pgraph_vk_get_framebuffer_surface(NV2AState *d)
@ -226,6 +226,8 @@ static PGRAPHRenderer pgraph_vk_renderer = {
.surface_update = pgraph_vk_surface_update,
.set_surface_scale_factor = pgraph_vk_set_surface_scale_factor,
.get_surface_scale_factor = pgraph_vk_get_surface_scale_factor,
.set_anisotropic_filter_level = pgraph_vk_set_anisotropic_filter_level,
.get_anisotropic_filter_level = pgraph_vk_get_anisotropic_filter_level,
.get_framebuffer_surface = pgraph_vk_get_framebuffer_surface,
}
};

View File

@ -545,6 +545,9 @@ void pgraph_vk_bind_textures(NV2AState *d);
void pgraph_vk_mark_textures_possibly_dirty(NV2AState *d, hwaddr addr,
hwaddr size);
void pgraph_vk_trim_texture_cache(PGRAPHState *pg);
void pgraph_vk_set_anisotropic_filter_level(NV2AState *d, unsigned int level_po2);
unsigned int pgraph_vk_get_anisotropic_filter_level(NV2AState *d);
void pgraph_vk_reload_anisotropic_filter_level(PGRAPHState *pg);
// shaders.c
void pgraph_vk_init_shaders(PGRAPHState *pg);

View File

@ -28,6 +28,7 @@
#include "hw/xbox/nv2a/pgraph/swizzle.h"
#include "qemu/fast-hash.h"
#include "qemu/lru.h"
#include "ui/xemu-settings.h"
#include "renderer.h"
static void texture_cache_release_node_resources(PGRAPHVkState *r, TextureBinding *snode);
@ -1345,9 +1346,8 @@ static void create_texture(PGRAPHState *pg, int texture_idx)
GET_MASK(address, NV_PGRAPH_TEXADDRESS0_ADDRV)),
.addressModeW = lookup_texture_address_mode(
GET_MASK(address, NV_PGRAPH_TEXADDRESS0_ADDRP)),
.anisotropyEnable = VK_FALSE,
// .anisotropyEnable = VK_TRUE,
// .maxAnisotropy = properties.limits.maxSamplerAnisotropy,
.anisotropyEnable = pg->anisotropic_filter_level >= 1,
.maxAnisotropy = 1 << pg->anisotropic_filter_level,
.borderColor = vk_border_color,
.compareEnable = VK_FALSE,
.compareOp = VK_COMPARE_OP_ALWAYS,
@ -1529,6 +1529,50 @@ void pgraph_vk_trim_texture_cache(PGRAPHState *pg)
NV2A_VK_DPRINTF("Evicted %d textures, %d remain", num_evicted, r->texture_cache.num_used);
}
void pgraph_vk_set_anisotropic_filter_level(NV2AState *d, unsigned int level_po2)
{
g_config.display.quality.anisotropic_filter_level = level_po2;
qemu_mutex_lock(&d->pfifo.lock);
qatomic_set(&d->pfifo.halt, true);
qemu_mutex_unlock(&d->pfifo.lock);
qemu_mutex_lock(&d->pgraph.lock);
qemu_event_reset(&d->pgraph.vk_renderer_state->dirty_surfaces_download_complete);
qatomic_set(&d->pgraph.vk_renderer_state->download_dirty_surfaces_pending, true);
qemu_mutex_unlock(&d->pgraph.lock);
qemu_mutex_lock(&d->pfifo.lock);
pfifo_kick(d);
qemu_mutex_unlock(&d->pfifo.lock);
qemu_event_wait(&d->pgraph.vk_renderer_state->dirty_surfaces_download_complete);
qemu_mutex_lock(&d->pgraph.lock);
qemu_event_reset(&d->pgraph.flush_complete);
qatomic_set(&d->pgraph.flush_pending, true);
qemu_mutex_unlock(&d->pgraph.lock);
qemu_mutex_lock(&d->pfifo.lock);
pfifo_kick(d);
qemu_mutex_unlock(&d->pfifo.lock);
qemu_event_wait(&d->pgraph.flush_complete);
qemu_mutex_lock(&d->pfifo.lock);
qatomic_set(&d->pfifo.halt, false);
pfifo_kick(d);
qemu_mutex_unlock(&d->pfifo.lock);
pgraph_vk_reload_anisotropic_filter_level(&d->pgraph);
}
unsigned int pgraph_vk_get_anisotropic_filter_level(NV2AState *d)
{
return d->pgraph.anisotropic_filter_level;
}
void pgraph_vk_reload_anisotropic_filter_level(PGRAPHState *pg)
{
pg->anisotropic_filter_level = g_config.display.quality.anisotropic_filter_level;
}
void pgraph_vk_init_textures(PGRAPHState *pg)
{
PGRAPHVkState *r = pg->vk_renderer_state;

View File

@ -172,14 +172,14 @@ void MainMenuInputView::Draw()
driver = DRIVER_DUKE_DISPLAY_NAME;
else if (strcmp(driver, DRIVER_S) == 0)
driver = DRIVER_S_DISPLAY_NAME;
ImGui::SetNextItemWidth(-FLT_MIN);
if (ImGui::BeginCombo("###InputDrivers", driver,
ImGuiComboFlags_NoArrowButton)) {
const char *available_drivers[] = { DRIVER_DUKE, DRIVER_S };
const char *driver_display_names[] = {
DRIVER_DUKE_DISPLAY_NAME,
DRIVER_S_DISPLAY_NAME
const char *driver_display_names[] = {
DRIVER_DUKE_DISPLAY_NAME,
DRIVER_S_DISPLAY_NAME
};
bool is_selected = false;
int num_drivers = sizeof(driver_display_names) / sizeof(driver_display_names[0]);
@ -513,10 +513,21 @@ void MainMenuDisplayView::Draw()
"8x\0"
"9x\0"
"10x\0",
"Increase surface scaling factor for higher quality")) {
"Increase surface scaling factor for higher overall quality")) {
nv2a_set_surface_scale_factor(rendering_scale+1);
}
int anisotropic_filter_level = nv2a_get_anisotropic_filter_level();
if (ChevronCombo("Anisotropic filtering level", &anisotropic_filter_level,
"Disabled\0"
"2x\0"
"4x\0"
"8x\0"
"16x\0",
"Increase anisotropic filtering level for sharper textures at oblique angles")) {
nv2a_set_anisotropic_filter_level(anisotropic_filter_level);
}
SectionTitle("Window");
bool fs = xemu_is_fullscreen();
if (Toggle("Fullscreen", &fs, "Enable fullscreen now")) {

View File

@ -192,6 +192,16 @@ void ShowMainMenu()
nv2a_set_surface_scale_factor(rendering_scale + 1);
}
int anisotropic_filter_level = nv2a_get_anisotropic_filter_level();
if (ImGui::Combo("Anisotropic Filtering Level", &anisotropic_filter_level,
"Disabled\0"
"2x\0"
"4x\0"
"8x\0"
"16x\0")) {
nv2a_set_anisotropic_filter_level(anisotropic_filter_level);
}
ImGui::Combo("Display Mode", &g_config.display.ui.fit,
"Center\0Scale\0Stretch\0");
ImGui::SameLine();