mirror of https://github.com/xemu-project/xemu.git
nv2a/gl/vk: Add an anisotropic filtering option to the graphics settings menu
This is available in both Vulkan and OpenGL renderers. Note that the Vulkan renderer requires a restart for changes to be effective, while changes in OpenGL are applied immediately.
This commit is contained in:
parent
a00820746f
commit
479c943dc9
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
};
|
||||
|
|
|
@ -284,6 +284,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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -406,6 +406,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)
|
||||
|
@ -3022,4 +3051,3 @@ void pgraph_pre_shutdown_wait(NV2AState *d)
|
|||
PGRAPHState *pg = &d->pgraph;
|
||||
pg->renderer->ops.pre_shutdown_wait(d);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
@ -241,6 +243,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;
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
};
|
||||
|
|
|
@ -544,6 +544,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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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")) {
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue