nv3089: Account for subpixel addressing

- Those strange offsets noted in some games seem to match to subpixel addressing.
  For example, when scaling down by a factor of 4, a pixel offset of 2 will end up inside pixel 0 of the output
This commit is contained in:
kd-11 2020-05-23 20:00:38 +03:00 committed by kd-11
parent 695b6e8f46
commit bd41a108d8
2 changed files with 29 additions and 25 deletions

View File

@ -1980,18 +1980,14 @@ namespace rsx
{
// TODO: Special case that needs wrapping around (custom blit)
rsx_log.error("Transfer cropped in Y, src_h=%d, offset_y=%d, block_h=%d", src_h, src.offset_y, src.height);
src_h = src.height - src.offset_y;
dst_h = u16(src_h * scale_y + 0.000001f);
}
if ((src_w + src.offset_x) > src.width) [[unlikely]]
{
// TODO: Special case that needs wrapping around (custom blit)
rsx_log.error("Transfer cropped in X, src_w=%d, offset_x=%d, block_w=%d", src_w, src.offset_x, src.width);
src_w = src.width - src.offset_x;
dst_w = u16(src_w * scale_x + 0.000001f);
}
}

View File

@ -980,11 +980,6 @@ namespace rsx
const f32 scale_x = method_registers.blit_engine_ds_dx();
const f32 scale_y = method_registers.blit_engine_dt_dy();
// NOTE: Do not round these value up!
// Sub-pixel offsets are used to signify pixel centers and do not mean to read from the next block (fill convention)
auto in_x = static_cast<u16>(std::floor(method_registers.blit_engine_in_x()));
auto in_y = static_cast<u16>(std::floor(method_registers.blit_engine_in_y()));
// Clipping
// Validate that clipping rect will fit onto both src and dst regions
const u16 clip_w = std::min(method_registers.blit_engine_clip_width(), out_w);
@ -1068,24 +1063,37 @@ namespace rsx
out_pitch = out_bpp * out_w;
}
if (in_x == 1 || in_y == 1) [[unlikely]]
if (in_bpp != out_bpp)
{
if (is_block_transfer && in_bpp == out_bpp)
{
// No scaling factor, so size in src == size in dst
// Check for texel wrapping where (offset + size) > size by 1 pixel
// TODO: Should properly RE this behaviour when I have time (kd-11)
if (in_x == 1 && in_w == clip_w) in_x = 0;
if (in_y == 1 && in_h == clip_h) in_y = 0;
}
else
{
// Graphics operation, ignore subpixel correction offsets
if (in_x == 1) in_x = 0;
if (in_y == 1) in_y = 0;
is_block_transfer = false;
}
is_block_transfer = false;
}
u16 in_x, in_y;
if (in_origin == blit_engine::transfer_origin::center)
{
// Convert to normal u,v addressing. Under this scheme offset of 1 is actually half-way inside pixel 0
const float x = std::max(method_registers.blit_engine_in_x(), 0.5f);
const float y = std::max(method_registers.blit_engine_in_y(), 0.5f);
in_x = static_cast<u16>(std::floor(x - 0.5f));
in_y = static_cast<u16>(std::floor(y - 0.5f));
}
else
{
in_x = static_cast<u16>(std::floor(method_registers.blit_engine_in_x()));
in_y = static_cast<u16>(std::floor(method_registers.blit_engine_in_y()));
}
// Check for subpixel addressing
if (scale_x < 1.f)
{
float dst_x = in_x * scale_x;
in_x = static_cast<u16>(std::floor(dst_x) / scale_x);
}
if (scale_y < 1.f)
{
float dst_y = in_y * scale_x;
in_y = static_cast<u16>(std::floor(dst_y) / scale_y);
}
const u32 in_offset = in_x * in_bpp + in_pitch * in_y;