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) // 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); 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; 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]] if ((src_w + src.offset_x) > src.width) [[unlikely]]
{ {
// TODO: Special case that needs wrapping around (custom blit) // 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); 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; 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_x = method_registers.blit_engine_ds_dx();
const f32 scale_y = method_registers.blit_engine_dt_dy(); 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 // Clipping
// Validate that clipping rect will fit onto both src and dst regions // 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); 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; 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) is_block_transfer = false;
}
u16 in_x, in_y;
if (in_origin == blit_engine::transfer_origin::center)
{ {
// No scaling factor, so size in src == size in dst // Convert to normal u,v addressing. Under this scheme offset of 1 is actually half-way inside pixel 0
// Check for texel wrapping where (offset + size) > size by 1 pixel const float x = std::max(method_registers.blit_engine_in_x(), 0.5f);
// TODO: Should properly RE this behaviour when I have time (kd-11) const float y = std::max(method_registers.blit_engine_in_y(), 0.5f);
if (in_x == 1 && in_w == clip_w) in_x = 0; in_x = static_cast<u16>(std::floor(x - 0.5f));
if (in_y == 1 && in_h == clip_h) in_y = 0; in_y = static_cast<u16>(std::floor(y - 0.5f));
} }
else else
{ {
// Graphics operation, ignore subpixel correction offsets in_x = static_cast<u16>(std::floor(method_registers.blit_engine_in_x()));
if (in_x == 1) in_x = 0; in_y = static_cast<u16>(std::floor(method_registers.blit_engine_in_y()));
if (in_y == 1) in_y = 0;
is_block_transfer = false;
} }
// 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; const u32 in_offset = in_x * in_bpp + in_pitch * in_y;