diff --git a/hw/xbox/nv2a/pgraph/gl/constants.h b/hw/xbox/nv2a/pgraph/gl/constants.h index d78b0054e3..ab5e9871ec 100644 --- a/hw/xbox/nv2a/pgraph/gl/constants.h +++ b/hw/xbox/nv2a/pgraph/gl/constants.h @@ -222,7 +222,7 @@ static const ColorFormatInfo kelvin_color_format_gl_map[66] = { {GL_RED, GL_RED, GL_RED, GL_GREEN}}, [NV097_SET_TEXTURE_FORMAT_COLOR_SZ_R6G5B5] = - {2, false, GL_RGB8_SNORM, GL_RGB, GL_BYTE}, /* FIXME: This might be signed */ + {2, false, GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE}, [NV097_SET_TEXTURE_FORMAT_COLOR_SZ_G8B8] = {2, false, GL_RG8, GL_RG, GL_UNSIGNED_BYTE, {GL_RED, GL_GREEN, GL_RED, GL_GREEN}}, @@ -276,6 +276,17 @@ static const ColorFormatInfo kelvin_color_format_gl_map[66] = { {4, true, GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8} }; +static const ColorFormatInfo kelvin_signed_color_format_gl_map[66] = { + [NV097_SET_TEXTURE_FORMAT_COLOR_SZ_R6G5B5] = + {2, false, GL_RGB8_SNORM, GL_RGB, GL_BYTE}, + [NV097_SET_TEXTURE_FORMAT_COLOR_SZ_G8B8] = + {2, false, GL_RG8_SNORM, GL_RG, GL_BYTE, + {GL_RED, GL_GREEN, GL_RED, GL_GREEN}}, + [NV097_SET_TEXTURE_FORMAT_COLOR_SZ_R8B8] = + {2, false, GL_RG8_SNORM, GL_RG, GL_BYTE, + {GL_GREEN, GL_RED, GL_RED, GL_GREEN}}, +}; + typedef struct SurfaceFormatInfo { unsigned int bytes_per_pixel; GLint gl_internal_format; @@ -319,4 +330,12 @@ static const SurfaceFormatInfo kelvin_surface_zeta_fixed_format_gl_map[] = { {4, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, GL_DEPTH_STENCIL_ATTACHMENT}, }; +static const uint32_t kelvin_signed_format_mask_gl_map[66] = { + [NV097_SET_TEXTURE_FORMAT_COLOR_SZ_R6G5B5] = + NV_PGRAPH_TEXFILTER0_RSIGNED | NV_PGRAPH_TEXFILTER0_GSIGNED | NV_PGRAPH_TEXFILTER0_BSIGNED, + [NV097_SET_TEXTURE_FORMAT_COLOR_SZ_G8B8] = + NV_PGRAPH_TEXFILTER0_GSIGNED | NV_PGRAPH_TEXFILTER0_BSIGNED, + [NV097_SET_TEXTURE_FORMAT_COLOR_SZ_R8B8] = + NV_PGRAPH_TEXFILTER0_RSIGNED | NV_PGRAPH_TEXFILTER0_BSIGNED +}; #endif diff --git a/hw/xbox/nv2a/pgraph/gl/renderer.h b/hw/xbox/nv2a/pgraph/gl/renderer.h index 3529006898..6b468f0b45 100644 --- a/hw/xbox/nv2a/pgraph/gl/renderer.h +++ b/hw/xbox/nv2a/pgraph/gl/renderer.h @@ -37,6 +37,7 @@ #include "gloffscreen.h" #include "constants.h" +#include typedef struct SurfaceBinding { QTAILQ_ENTRY(SurfaceBinding) entry; @@ -271,7 +272,7 @@ void pgraph_gl_init_buffers(NV2AState *d); void pgraph_gl_finalize_buffers(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); +void pgraph_gl_render_surface_to_texture(NV2AState *d, SurfaceBinding *surface, TextureBinding *texture, TextureShape *texture_shape, int texture_unit, uint32_t filter); void pgraph_gl_set_surface_dirty(PGRAPHState *pg, bool color, bool zeta); void pgraph_gl_surface_download_if_dirty(NV2AState *d, SurfaceBinding *surface); SurfaceBinding *pgraph_gl_surface_get(NV2AState *d, hwaddr addr); diff --git a/hw/xbox/nv2a/pgraph/gl/surface.c b/hw/xbox/nv2a/pgraph/gl/surface.c index 53df185130..13acf5cc4e 100644 --- a/hw/xbox/nv2a/pgraph/gl/surface.c +++ b/hw/xbox/nv2a/pgraph/gl/surface.c @@ -25,6 +25,7 @@ #include "hw/xbox/nv2a/pgraph/swizzle.h" #include "debug.h" #include "renderer.h" +#include static void surface_download(NV2AState *d, SurfaceBinding *surface, bool force); static void surface_download_to_buffer(NV2AState *d, SurfaceBinding *surface, @@ -280,11 +281,16 @@ static void render_surface_to_texture_slow(NV2AState *d, SurfaceBinding *surface, TextureBinding *texture, TextureShape *texture_shape, - int texture_unit) + int texture_unit, + uint32_t filter) { PGRAPHState *pg = &d->pgraph; - const ColorFormatInfo *f = &kelvin_color_format_gl_map[texture_shape->color_format]; + ColorFormatInfo f = kelvin_color_format_gl_map[texture_shape->color_format]; + uint32_t mask = kelvin_signed_format_mask_gl_map[texture_shape->color_format]; + if (mask && (filter & mask) == mask) + f = kelvin_signed_color_format_gl_map[texture_shape->color_format]; + assert(texture_shape->color_format < ARRAY_SIZE(kelvin_color_format_gl_map)); nv2a_profile_inc_counter(NV2A_PROF_SURF_TO_TEX_FALLBACK); @@ -304,8 +310,8 @@ static void render_surface_to_texture_slow(NV2AState *d, height = texture_shape->height; pgraph_apply_scaling_factor(pg, &width, &height); - glTexImage2D(texture->gl_target, 0, f->gl_internal_format, width, height, 0, - f->gl_format, f->gl_type, buf); + glTexImage2D(texture->gl_target, 0, f.gl_internal_format, width, height, 0, + f.gl_format, f.gl_type, buf); g_free(buf); glBindTexture(texture->gl_target, texture->gl_texture); } @@ -317,20 +323,23 @@ static void render_surface_to_texture_slow(NV2AState *d, void pgraph_gl_render_surface_to_texture(NV2AState *d, SurfaceBinding *surface, TextureBinding *texture, TextureShape *texture_shape, - int texture_unit) + int texture_unit, + uint32_t filter) { PGRAPHState *pg = &d->pgraph; PGRAPHGLState *r = pg->gl_renderer_state; - const ColorFormatInfo *f = - &kelvin_color_format_gl_map[texture_shape->color_format]; + ColorFormatInfo f = kelvin_color_format_gl_map[texture_shape->color_format]; + uint32_t mask = kelvin_signed_format_mask_gl_map[texture_shape->color_format]; + if (mask && (filter & mask) == mask) + f = kelvin_signed_color_format_gl_map[texture_shape->color_format]; assert(texture_shape->color_format < ARRAY_SIZE(kelvin_color_format_gl_map)); nv2a_profile_inc_counter(NV2A_PROF_SURF_TO_TEX); if (!surface_to_texture_can_fastpath(surface, texture_shape)) { render_surface_to_texture_slow(d, surface, texture, - texture_shape, texture_unit); + texture_shape, texture_unit, filter); return; } @@ -342,8 +351,8 @@ void pgraph_gl_render_surface_to_texture(NV2AState *d, SurfaceBinding *surface, glTexParameteri(texture->gl_target, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(texture->gl_target, GL_TEXTURE_MAX_LEVEL, 0); glTexParameteri(texture->gl_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexImage2D(texture->gl_target, 0, f->gl_internal_format, width, height, 0, - f->gl_format, f->gl_type, NULL); + glTexImage2D(texture->gl_target, 0, f.gl_internal_format, width, height, 0, + f.gl_format, f.gl_type, NULL); glBindTexture(texture->gl_target, 0); render_surface_to(d, surface, texture_unit, texture->gl_target, texture->gl_texture, width, height); diff --git a/hw/xbox/nv2a/pgraph/gl/texture.c b/hw/xbox/nv2a/pgraph/gl/texture.c index 317fcc1070..404bf3a150 100644 --- a/hw/xbox/nv2a/pgraph/gl/texture.c +++ b/hw/xbox/nv2a/pgraph/gl/texture.c @@ -24,10 +24,12 @@ #include "hw/xbox/nv2a/pgraph/swizzle.h" #include "hw/xbox/nv2a/pgraph/s3tc.h" #include "hw/xbox/nv2a/pgraph/texture.h" +#include "constants.h" #include "debug.h" #include "renderer.h" +#include -static TextureBinding* generate_texture(const TextureShape s, const uint8_t *texture_data, const uint8_t *palette_data); +static TextureBinding* generate_texture(const TextureShape s, const uint8_t *texture_data, const uint8_t *palette_data, uint32_t filter); static void texture_binding_destroy(gpointer data); struct pgraph_texture_possibly_dirty_struct { @@ -343,7 +345,7 @@ void pgraph_gl_bind_textures(NV2AState *d) if (key_out->binding == NULL) { // Must create the texture - key_out->binding = generate_texture(state, texture_data, palette_data); + key_out->binding = generate_texture(state, texture_data, palette_data, filter); key_out->binding->data_hash = tex_data_hash; key_out->binding->scale = 1; } else { @@ -360,7 +362,7 @@ void pgraph_gl_bind_textures(NV2AState *d) trace_nv2a_pgraph_surface_render_to_texture( surface->vram_addr, surface->width, surface->height); - pgraph_gl_render_surface_to_texture(d, surface, binding, &state, i); + pgraph_gl_render_surface_to_texture(d, surface, binding, &state, i, filter); binding->draw_time = surface->draw_time; binding->scale = pg->surface_scale_factor; } @@ -403,9 +405,14 @@ gl_internal_format_to_s3tc_enum(GLint gl_internal_format) static void upload_gl_texture(GLenum gl_target, const TextureShape s, const uint8_t *texture_data, - const uint8_t *palette_data) + const uint8_t *palette_data, + uint32_t filter) { ColorFormatInfo f = kelvin_color_format_gl_map[s.color_format]; + uint32_t mask = kelvin_signed_format_mask_gl_map[s.color_format]; + if (mask && (filter & mask) == mask) + f = kelvin_signed_color_format_gl_map[s.color_format]; + nv2a_profile_inc_counter(NV2A_PROF_TEX_UPLOAD); unsigned int adjusted_width = s.width; @@ -620,9 +627,13 @@ static void upload_gl_texture(GLenum gl_target, static TextureBinding* generate_texture(const TextureShape s, const uint8_t *texture_data, - const uint8_t *palette_data) + const uint8_t *palette_data, + uint32_t filter) { ColorFormatInfo f = kelvin_color_format_gl_map[s.color_format]; + uint32_t mask = kelvin_signed_format_mask_gl_map[s.color_format]; + if (mask && (filter & mask) == mask) + f = kelvin_signed_color_format_gl_map[s.color_format]; /* Create a new opengl texture */ GLuint gl_texture; @@ -690,19 +701,19 @@ static TextureBinding* generate_texture(const TextureShape s, length = (length + NV2A_CUBEMAP_FACE_ALIGNMENT - 1) & ~(NV2A_CUBEMAP_FACE_ALIGNMENT - 1); upload_gl_texture(GL_TEXTURE_CUBE_MAP_POSITIVE_X, - s, texture_data + 0 * length, palette_data); + s, texture_data + 0 * length, palette_data, filter); upload_gl_texture(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, - s, texture_data + 1 * length, palette_data); + s, texture_data + 1 * length, palette_data, filter); upload_gl_texture(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, - s, texture_data + 2 * length, palette_data); + s, texture_data + 2 * length, palette_data, filter); upload_gl_texture(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, - s, texture_data + 3 * length, palette_data); + s, texture_data + 3 * length, palette_data, filter); upload_gl_texture(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, - s, texture_data + 4 * length, palette_data); + s, texture_data + 4 * length, palette_data, filter); upload_gl_texture(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, - s, texture_data + 5 * length, palette_data); + s, texture_data + 5 * length, palette_data, filter); } else { - upload_gl_texture(gl_target, s, texture_data, palette_data); + upload_gl_texture(gl_target, s, texture_data, palette_data, filter); } /* Linear textures don't support mipmapping */