Skip to content

Commit

Permalink
nv2a: Normalize unnormalized texture coordinates in shader
Browse files Browse the repository at this point in the history
  • Loading branch information
mborgerson committed Jul 30, 2024
1 parent 0ec6375 commit 08f3f98
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 132 deletions.
60 changes: 24 additions & 36 deletions hw/xbox/nv2a/pgraph/gl/texture.c
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,6 @@ void pgraph_gl_bind_textures(NV2AState *d)
glActiveTexture(GL_TEXTURE0 + i);
if (!enabled) {
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
glBindTexture(GL_TEXTURE_RECTANGLE, 0);
glBindTexture(GL_TEXTURE_1D, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindTexture(GL_TEXTURE_3D, 0);
Expand Down Expand Up @@ -363,11 +362,7 @@ void pgraph_gl_bind_textures(NV2AState *d)
surface->vram_addr, surface->width, surface->height);
pgraph_gl_render_surface_to_texture(d, surface, binding, &state, i);
binding->draw_time = surface->draw_time;
if (binding->gl_target == GL_TEXTURE_RECTANGLE) {
binding->scale = pg->surface_scale_factor;
} else {
binding->scale = 1;
}
binding->scale = pg->surface_scale_factor;
}

apply_texture_parameters(binding,
Expand Down Expand Up @@ -428,28 +423,29 @@ static void upload_gl_texture(GLenum gl_target,
case GL_TEXTURE_1D:
assert(false);
break;
case GL_TEXTURE_RECTANGLE: {
/* Can't handle strides unaligned to pixels */
assert(s.pitch % f.bytes_per_pixel == 0);

uint8_t *converted = pgraph_convert_texture_data(
s, texture_data, palette_data, adjusted_width, adjusted_height, 1,
adjusted_pitch, 0, NULL);
glPixelStorei(GL_UNPACK_ROW_LENGTH,
converted ? 0 : adjusted_pitch / f.bytes_per_pixel);
glTexImage2D(gl_target, 0, f.gl_internal_format,
adjusted_width, adjusted_height, 0,
f.gl_format, f.gl_type,
converted ? converted : texture_data);

if (converted) {
g_free(converted);
}

glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
break;
}
case GL_TEXTURE_2D:
if (f.linear) {
/* Can't handle strides unaligned to pixels */
assert(s.pitch % f.bytes_per_pixel == 0);

uint8_t *converted = pgraph_convert_texture_data(
s, texture_data, palette_data, adjusted_width, adjusted_height, 1,
adjusted_pitch, 0, NULL);
glPixelStorei(GL_UNPACK_ROW_LENGTH,
converted ? 0 : adjusted_pitch / f.bytes_per_pixel);
glTexImage2D(GL_TEXTURE_2D, 0, f.gl_internal_format,
adjusted_width, adjusted_height, 0,
f.gl_format, f.gl_type,
converted ? converted : texture_data);

if (converted) {
g_free(converted);
}

glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
break;
}
/* fallthru */
case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
Expand Down Expand Up @@ -645,15 +641,7 @@ static TextureBinding* generate_texture(const TextureShape s,
gl_target = GL_TEXTURE_CUBE_MAP;
} else {
if (f.linear) {
/* linear textures use unnormalised texcoords.
* GL_TEXTURE_RECTANGLE_ARB conveniently also does, but
* does not allow repeat and mirror wrap modes.
* (or mipmapping, but xbox d3d says 'Non swizzled and non
* compressed textures cannot be mip mapped.')
* Not sure if that'll be an issue. */

/* FIXME: GLSL 330 provides us with textureSize()! Use that? */
gl_target = GL_TEXTURE_RECTANGLE;
gl_target = GL_TEXTURE_2D;
assert(s.dimensionality == 2);
} else {
switch(s.dimensionality) {
Expand Down
130 changes: 41 additions & 89 deletions hw/xbox/nv2a/pgraph/glsl/psh.c
Original file line number Diff line number Diff line change
Expand Up @@ -562,31 +562,13 @@ static void add_final_stage_code(struct PixelShader *ps, struct FCInputInfo fina
ps->varE = ps->varF = NULL;
}

static enum PS_TEXTUREMODES correct_texture_mode_for_dimensionality(enum PS_TEXTUREMODES mode, const PshState *state, int i)
static const char *get_sampler_type(enum PS_TEXTUREMODES mode, const PshState *state, int i)
{
const char *sampler2D = "sampler2D";
const char *sampler3D = "sampler3D";
const char *samplerCube = "samplerCube";
int dim = state->dim_tex[i];

switch (mode) {
case PS_TEXTUREMODES_PROJECT2D:
return dim == 2 ? PS_TEXTUREMODES_PROJECT2D :
dim == 3 ? PS_TEXTUREMODES_PROJECT3D :
mode;
case PS_TEXTUREMODES_PROJECT3D:
return dim == 2 ? PS_TEXTUREMODES_PROJECT2D : mode;
case PS_TEXTUREMODES_DOT_STR_3D:
return dim == 2 ? PS_TEXTUREMODES_DOT_ST : mode;
default:
return mode;
}
}

static const char sampler2D[] = "sampler2D";
static const char sampler3D[] = "sampler3D";
static const char samplerCube[] = "samplerCube";
static const char sampler2DRect[] = "sampler2DRect";

static const char* get_sampler_type(enum PS_TEXTUREMODES mode, const PshState *state, int i)
{
// FIXME: Cleanup
switch (mode) {
default:
Expand All @@ -598,7 +580,7 @@ static const char* get_sampler_type(enum PS_TEXTUREMODES mode, const PshState *s
if (state->tex_x8y24[i] && state->vulkan) {
return "usampler2D";
}
return (state->rect_tex[i] && !state->vulkan) ? sampler2DRect : sampler2D;
return sampler2D;

case PS_TEXTUREMODES_BUMPENVMAP:
case PS_TEXTUREMODES_BUMPENVMAP_LUM:
Expand All @@ -608,18 +590,17 @@ static const char* get_sampler_type(enum PS_TEXTUREMODES mode, const PshState *s
assert(!"Shadow map support not implemented for this mode");
}
assert(state->dim_tex[i] == 2);
return (state->rect_tex[i] && !state->vulkan) ? sampler2DRect : sampler2D;
return sampler2D;

case PS_TEXTUREMODES_PROJECT3D:
case PS_TEXTUREMODES_DOT_STR_3D:
if (state->tex_x8y24[i] && state->vulkan) {
return "usampler2D";
}
if (state->shadow_map[i]) {
return (state->rect_tex[i] && !state->vulkan) ? sampler2DRect : sampler2D;
return sampler2D;
}
assert(state->dim_tex[i] == 3);
return sampler3D;
return dim == 2 ? sampler2D : sampler3D;

case PS_TEXTUREMODES_CUBEMAP:
case PS_TEXTUREMODES_DOT_RFLCT_DIFF:
Expand Down Expand Up @@ -664,27 +645,19 @@ static void psh_append_shadowmap(const struct PixelShader *ps, int i, bool compa
return;
}

mstring_append_fmt(vars, "pT%d.xy *= texScale%d;\n", i, i);
const char *comparison = shadow_comparison_map[ps->state.shadow_depth_func];
if (ps->state.rect_tex[i] && ps->state.vulkan) {
if (ps->state.tex_x8y24[i]) {
mstring_append_fmt(
vars,
"uvec4 t%d_depth_raw = textureLod(texSamp%d, pT%d.xy/pT%d.w, 0);\n", i, i, i, i);
mstring_append_fmt(
vars,
"vec4 t%d_depth = vec4(float(t%d_depth_raw.x >> 8) / 0xFFFFFF, 1.0, 0.0, 0.0);\n",
i, i);
} else {
mstring_append_fmt(
vars,
"vec4 t%d_depth = textureLod(texSamp%d, pT%d.xy/pT%d.w, 0);\n", i,
i, i, i);
}
} else {
mstring_append_fmt(
vars, "vec4 t%d_depth = textureProj(texSamp%d, pT%d.xyw);\n", i, i,
i);

bool extract_msb_24b = ps->state.tex_x8y24[i] && ps->state.vulkan;

mstring_append_fmt(vars,
"%svec4 t%d_depth%s = textureProj(texSamp%d, pT%d.xyw);\n",
extract_msb_24b ? "u" : "", i, extract_msb_24b ? "_raw" : "", i, i);

if (extract_msb_24b) {
mstring_append_fmt(vars,
"vec4 t%d_depth = vec4(float(t%d_depth_raw.x >> 8) "
"/ 0xFFFFFF, 1.0, 0.0, 0.0);\n",
i, i);
}

// Depth.y != 0 indicates 24 bit; depth.z != 0 indicates float.
Expand Down Expand Up @@ -733,26 +706,13 @@ static void apply_border_adjustment(const struct PixelShader *ps, MString *vars,

static void apply_convolution_filter(const struct PixelShader *ps, MString *vars, int tex)
{
// FIXME: Convolution for 2D textures
// FIXME: Quincunx
assert(ps->state.rect_tex[tex]);

if (ps->state.vulkan) {
mstring_append_fmt(vars,
"vec4 t%d = vec4(0.0);\n"
"for (int i = 0; i < 9; i++) {\n"
" vec2 texCoord = pT%d.xy/pT%d.w + convolution3x3[i];\n"
" t%d += textureLod(texSamp%d, texCoord, 0) * gaussian3x3[i];\n"
"}\n", tex, tex, tex, tex, tex);
} else {
mstring_append_fmt(vars,
"vec4 t%d = vec4(0.0);\n"
"for (int i = 0; i < 9; i++) {\n"
" vec3 texCoord = pT%d.xyw + vec3(convolution3x3[i], 0);\n"
" t%d += textureProj(texSamp%d, texCoord) * gaussian3x3[i];\n"
"}\n", tex, tex, tex, tex, tex);

}
mstring_append_fmt(vars,
"vec4 t%d = vec4(0.0);\n"
"for (int i = 0; i < 9; i++) {\n"
" vec3 texCoord = pT%d.xyw + vec3(convolution3x3[i] / (textureSize(texSamp%d, 0) * texScale%d), 0);\n"
" t%d += textureProj(texSamp%d, texCoord) * gaussian3x3[i];\n"
"}\n", tex, tex, tex, tex, tex, tex, tex);
}

static MString* psh_convert(struct PixelShader *ps)
Expand Down Expand Up @@ -924,6 +884,12 @@ static MString* psh_convert(struct PixelShader *ps)

ps->code = mstring_new();

for (i = 0; i < 4; i++) {
if (ps->state.rect_tex[i]) {
mstring_append_fmt(vars, "pT%d.xy /= textureSize(texSamp%d, 0) / texScale%d;\n", i, i, i);
}
}

for (i = 0; i < 4; i++) {

const char *sampler_type = get_sampler_type(ps->tex_modes[i], &ps->state, i);
Expand All @@ -944,22 +910,9 @@ static MString* psh_convert(struct PixelShader *ps)
psh_append_shadowmap(ps, i, false, vars);
} else {
apply_border_adjustment(ps, vars, i, "pT%d");
mstring_append_fmt(vars, "pT%d.xy = texScale%d * pT%d.xy;\n", i, i, i);
if (ps->state.rect_tex[i]) {
if ((ps->state.conv_tex[i] ==
CONVOLUTION_FILTER_GAUSSIAN) ||
(ps->state.conv_tex[i] ==
CONVOLUTION_FILTER_QUINCUNX)) {
apply_convolution_filter(ps, vars, i);
} else {
if (ps->state.vulkan) {
mstring_append_fmt(vars, "vec4 t%d = textureLod(texSamp%d, pT%d.xy/pT%d.w, 0);\n",
i, i, i, i);
} else {
mstring_append_fmt(vars, "vec4 t%d = textureProj(texSamp%d, pT%d.xyw);\n",
i, i, i);
}
}
if (((ps->state.conv_tex[i] == CONVOLUTION_FILTER_GAUSSIAN) ||
(ps->state.conv_tex[i] == CONVOLUTION_FILTER_QUINCUNX))) {
apply_convolution_filter(ps, vars, i);
} else {
mstring_append_fmt(vars, "vec4 t%d = textureProj(texSamp%d, pT%d.xyw);\n",
i, i, i);
Expand Down Expand Up @@ -1011,8 +964,8 @@ static MString* psh_convert(struct PixelShader *ps)

mstring_append_fmt(vars, "dsdt%d = bumpMat%d * dsdt%d;\n",
i, i, i, i);
mstring_append_fmt(vars, "vec4 t%d = texture(texSamp%d, texScale%d * (pT%d.xy + dsdt%d));\n",
i, i, i, i, i);
mstring_append_fmt(vars, "vec4 t%d = texture(texSamp%d, (pT%d.xy + dsdt%d));\n",
i, i, i, i);
break;
case PS_TEXTUREMODES_BUMPENVMAP_LUM:
assert(i >= 1);
Expand All @@ -1029,8 +982,8 @@ static MString* psh_convert(struct PixelShader *ps)

mstring_append_fmt(vars, "dsdtl%d.st = bumpMat%d * dsdtl%d.st;\n",
i, i, i, i);
mstring_append_fmt(vars, "vec4 t%d = texture(texSamp%d, texScale%d * (pT%d.xy + dsdtl%d.st));\n",
i, i, i, i, i);
mstring_append_fmt(vars, "vec4 t%d = texture(texSamp%d, (pT%d.xy + dsdtl%d.st));\n",
i, i, i, i);
mstring_append_fmt(vars, "t%d = t%d * (bumpScale%d * dsdtl%d.p + bumpOffset%d);\n",
i, i, i, i, i);
break;
Expand All @@ -1049,8 +1002,8 @@ static MString* psh_convert(struct PixelShader *ps)
i, i, dotmap_func, ps->input_tex[i], i, i-1, i);

apply_border_adjustment(ps, vars, i, "dotST%d");
mstring_append_fmt(vars, "vec4 t%d = texture(texSamp%d, texScale%d * dotST%d);\n",
i, i, i, i);
mstring_append_fmt(vars, "vec4 t%d = texture(texSamp%d, dotST%d);\n",
i, i, i);
break;
case PS_TEXTUREMODES_DOT_ZW:
assert(i >= 2);
Expand Down Expand Up @@ -1272,7 +1225,6 @@ MString *pgraph_gen_psh_glsl(const PshState state)
ps.flags = state.combiner_control >> 8;
for (i = 0; i < 4; i++) {
ps.tex_modes[i] = (state.shader_stage_program >> (i * 5)) & 0x1F;
ps.tex_modes[i] = correct_texture_mode_for_dimensionality(ps.tex_modes[i], &state, i);
}

ps.dot_map[0] = 0;
Expand Down
7 changes: 0 additions & 7 deletions hw/xbox/nv2a/pgraph/vk/texture.c
Original file line number Diff line number Diff line change
Expand Up @@ -1305,12 +1305,6 @@ static void create_texture(PGRAPHState *pg, int texture_idx)
if (is_linear_filter_supported_for_format(r, state.color_format)) {
vk_mag_filter = pgraph_texture_min_filter_vk_map[mag_filter];
vk_min_filter = pgraph_texture_min_filter_vk_map[min_filter];

if (f_basic.linear && vk_mag_filter != vk_min_filter) {
// FIXME: Per spec, if coordinates unnormalized, filters must be
// same.
vk_mag_filter = vk_min_filter = VK_FILTER_LINEAR;
}
} else {
vk_mag_filter = vk_min_filter = VK_FILTER_NEAREST;
}
Expand Down Expand Up @@ -1343,7 +1337,6 @@ static void create_texture(PGRAPHState *pg, int texture_idx)
// .anisotropyEnable = VK_TRUE,
// .maxAnisotropy = properties.limits.maxSamplerAnisotropy,
.borderColor = vk_border_color,
.unnormalizedCoordinates = f_basic.linear ? VK_TRUE : VK_FALSE,
.compareEnable = VK_FALSE,
.compareOp = VK_COMPARE_OP_ALWAYS,
.mipmapMode = mipmap_nearest ? VK_SAMPLER_MIPMAP_MODE_NEAREST :
Expand Down

0 comments on commit 08f3f98

Please sign in to comment.