Skip to content

Commit

Permalink
[renderer] Correctly handle textures with height > width.
Browse files Browse the repository at this point in the history
  • Loading branch information
Senryoku committed Jul 13, 2024
1 parent cab2741 commit 84f33fd
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 16 deletions.
2 changes: 1 addition & 1 deletion libs/arm7
31 changes: 18 additions & 13 deletions src/Renderer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1126,7 +1126,7 @@ pub const Renderer = struct {
const stride_select = if (is_paletted) 0 else texture_control_word.stride_select;

const twiddled = scan_order == 0;
const size_index = tsp_instruction.texture_u_size;
const size_index = @max(tsp_instruction.texture_u_size, tsp_instruction.texture_v_size);

// NOTE: This is used by stride textures. Stride textures actual size can be smaller than their allocated size, but UV calculation are still done with it.
const alloc_u_size = (@as(u16, 8) << tsp_instruction.texture_u_size);
Expand Down Expand Up @@ -1299,11 +1299,11 @@ pub const Renderer = struct {
}
if (texture_index == InvalidTextureIndex) {
// Search for the last recently used texture, preferring an outdated one.
for (0..Renderer.MaxTextures[size_index]) |i| {
if (self.texture_metadata[size_index][i].status == .Outdated and (texture_index == InvalidTextureIndex or self.texture_metadata[size_index][texture_index].status == .Unused or (self.texture_metadata[size_index][texture_index].status == .Outdated and self.texture_metadata[size_index][texture_index].age < self.texture_metadata[size_index][i].age))) {
texture_index = @as(TextureIndex, @intCast(i));
} else if (self.texture_metadata[size_index][i].status == .Unused and (texture_index == InvalidTextureIndex or self.texture_metadata[size_index][texture_index].age < self.texture_metadata[size_index][i].age)) {
texture_index = @as(TextureIndex, @intCast(i));
for (self.texture_metadata[size_index][0..Renderer.MaxTextures[size_index]], 0..) |*entry, idx| {
if (entry.status == .Outdated and (texture_index == InvalidTextureIndex or self.texture_metadata[size_index][texture_index].status == .Unused or (self.texture_metadata[size_index][texture_index].status == .Outdated and self.texture_metadata[size_index][texture_index].age < entry.age))) {
texture_index = @as(TextureIndex, @intCast(idx));
} else if (entry.status == .Unused and (texture_index == InvalidTextureIndex or self.texture_metadata[size_index][texture_index].age < entry.age)) {
texture_index = @as(TextureIndex, @intCast(idx));
}
}
}
Expand Down Expand Up @@ -1337,13 +1337,18 @@ pub const Renderer = struct {
.palette_hash = palette_hash(gpu, texture_control_word),
};

// Fill with repeating texture data when v_size < u_size to avoid vertical wrapping artifacts.
// FIXME: We should do the same the stride textures when u_size < alloc_u_size.
for (0..u_size / v_size) |part| {
// Fill with repeating texture data when v_size != u_size to avoid wrapping artifacts.
const repeat_vertically = v_size <= u_size;
const copies = if (repeat_vertically) u_size / v_size else v_size / u_size;
for (0..copies) |part| {
self._gctx.queue.writeTexture(
.{
.texture = self._gctx.lookupResource(self.texture_arrays[size_index]).?,
.origin = .{ .y = @intCast(v_size * part), .z = @intCast(texture_index) },
.origin = .{
.x = if (repeat_vertically) 0 else @intCast(u_size * part),
.y = if (repeat_vertically) @intCast(v_size * part) else 0,
.z = @intCast(texture_index),
},
},
.{
.bytes_per_row = u_size * 4,
Expand Down Expand Up @@ -1484,7 +1489,7 @@ pub const Renderer = struct {
const isp_tsp_instruction = @as(*const HollyModule.ISPTSPInstructionWord, @alignCast(@ptrCast(&gpu.vram[addr]))).*;
const tsp_instruction = @as(*const HollyModule.TSPInstructionWord, @alignCast(@ptrCast(&gpu.vram[addr + 4]))).*;
const texture_control = @as(*const HollyModule.TextureControlWord, @alignCast(@ptrCast(&gpu.vram[addr + 8]))).*;
const texture_size_index = tsp_instruction.texture_u_size;
const texture_size_index = @max(tsp_instruction.texture_u_size, tsp_instruction.texture_v_size);

// FIXME: I don't understand. In the boot menu for example, this depth value is 0.0,
// which doesn't make sense. The vertices z position looks more inline with what
Expand Down Expand Up @@ -1525,7 +1530,7 @@ pub const Renderer = struct {
.textured = isp_tsp_instruction.texture,
.mode = tsp_instruction.texture_shading_instruction,
.ignore_alpha = tsp_instruction.ignore_texture_alpha,
.tex_u_size = texture_size_index,
.tex_u_size = tsp_instruction.texture_u_size,
.tex_v_size = tsp_instruction.texture_v_size,
.depth_compare = isp_tsp_instruction.depth_compare_mode,
.fog_control = tsp_instruction.fog_control,
Expand Down Expand Up @@ -1747,7 +1752,7 @@ pub const Renderer = struct {

var tex_idx: TextureIndex = 0;
const textured = parameter_control_word.obj_control.texture == 1;
const texture_size_index = tsp_instruction.texture_u_size;
const texture_size_index = @max(tsp_instruction.texture_u_size, tsp_instruction.texture_v_size);
if (textured) {
const tmp_tex_idx = self.get_texture_index(gpu, texture_size_index, texture_control);
if (tmp_tex_idx == null) {
Expand Down
5 changes: 3 additions & 2 deletions src/shaders/fragment_color.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ fn tex_sample(uv: vec2<f32>, control: u32, index: u32) -> vec4<f32> {
// This kinda feel like a hack, but works.
let ddx = dpdx(uv);
let ddy = dpdy(uv);
switch((control >> 4) & 7) {
switch(max((control >> 4) & 7, (control >> 7) & 7)) {
case 0u: { return textureSampleGrad(texture_array_8x8, image_sampler, uv, index, ddx, ddy); }
case 1u: { return textureSampleGrad(texture_array_16x16, image_sampler, uv, index, ddx, ddy); }
case 2u: { return textureSampleGrad(texture_array_32x32, image_sampler, uv, index, ddx, ddy); }
Expand Down Expand Up @@ -100,7 +100,8 @@ fn fragment_color(
) -> FragmentColor {
let u_size: f32 = tex_size((tex[1] >> 4) & 7);
let v_size: f32 = tex_size((tex[1] >> 7) & 7);
let tex_color = tex_sample( vec2<f32>(1.0, v_size / u_size) * uv, tex[1], tex[0]);
let uv_factor = select(vec2<f32>(1.0, v_size / u_size), vec2<f32>(u_size / v_size, 1.0), u_size < v_size);
let tex_color = tex_sample(uv_factor * uv, tex[1], tex[0]);

var final_color = base_color + vec4<f32>(offset_color.rgb, 0.0);

Expand Down

0 comments on commit 84f33fd

Please sign in to comment.