From c1634680caa0f9c1b2e80bf961c16ec5b27b87dd Mon Sep 17 00:00:00 2001 From: invertego Date: Sun, 12 Mar 2023 09:54:11 -0700 Subject: emu/rgbgen.h: Made out-of-range shift deterministic. (#10987) Matches the SSE and VMX implementation. Fixes obvious rendering artefacts with the N64 RDP on AArch64 targets. --- src/emu/validity.cpp | 63 ++++++++++++++++++++++++++++++++++++++++++++++ src/emu/video/rgbgen.h | 68 ++++++++++++++++++++------------------------------ 2 files changed, 90 insertions(+), 41 deletions(-) diff --git a/src/emu/validity.cpp b/src/emu/validity.cpp index 831328cbb10..7665acedd13 100644 --- a/src/emu/validity.cpp +++ b/src/emu/validity.cpp @@ -836,6 +836,15 @@ void validate_rgb() rgb.shl(rgbaint_t(19, 3, 21, 6)); check_expected("rgbaint_t::shl"); + // test shift left out of range + expected_a = (actual_a = random_i32()) & 0; + expected_r = (actual_r = random_i32()) & 0; + expected_g = (actual_g = random_i32()) & 0; + expected_b = (actual_b = random_i32()) & 0; + rgb.set(actual_a, actual_r, actual_g, actual_b); + rgb.shl(rgbaint_t(-19, 32, -21, 38)); + check_expected("rgbaint_t::shl"); + // test shift left immediate expected_a = (actual_a = random_i32()) << 7; expected_r = (actual_r = random_i32()) << 7; @@ -845,6 +854,15 @@ void validate_rgb() rgb.shl_imm(7); check_expected("rgbaint_t::shl_imm"); + // test shift left immediate out of range + expected_a = (actual_a = random_i32()) & 0; + expected_r = (actual_r = random_i32()) & 0; + expected_g = (actual_g = random_i32()) & 0; + expected_b = (actual_b = random_i32()) & 0; + rgb.set(actual_a, actual_r, actual_g, actual_b); + rgb.shl_imm(32); + check_expected("rgbaint_t::shl_imm"); + // test logical shift right expected_a = s32(u32(actual_a = random_i32()) >> 8); expected_r = s32(u32(actual_r = random_i32()) >> 18); @@ -863,6 +881,15 @@ void validate_rgb() rgb.shr(rgbaint_t(21, 13, 11, 17)); check_expected("rgbaint_t::shr"); + // test logical shift right out of range + expected_a = (actual_a = random_i32()) & 0; + expected_r = (actual_r = random_i32()) & 0; + expected_g = (actual_g = random_i32()) & 0; + expected_b = (actual_b = random_i32()) & 0; + rgb.set(actual_a, actual_r, actual_g, actual_b); + rgb.shr(rgbaint_t(40, -18, -26, 32)); + check_expected("rgbaint_t::shr"); + // test logical shift right immediate expected_a = s32(u32(actual_a = random_i32()) >> 5); expected_r = s32(u32(actual_r = random_i32()) >> 5); @@ -881,6 +908,15 @@ void validate_rgb() rgb.shr_imm(15); check_expected("rgbaint_t::shr_imm"); + // test logical shift right immediate out of range + expected_a = (actual_a = random_i32()) & 0; + expected_r = (actual_r = random_i32()) & 0; + expected_g = (actual_g = random_i32()) & 0; + expected_b = (actual_b = random_i32()) & 0; + rgb.set(actual_a, actual_r, actual_g, actual_b); + rgb.shr_imm(35); + check_expected("rgbaint_t::shr_imm"); + // test arithmetic shift right expected_a = (actual_a = random_i32()) >> 16; expected_r = (actual_r = random_i32()) >> 20; @@ -899,6 +935,15 @@ void validate_rgb() rgb.sra(rgbaint_t(1, 29, 10, 22)); check_expected("rgbaint_t::sra"); + // test arithmetic shift right out of range + expected_a = (actual_a = random_i32()) >> 31; + expected_r = (actual_r = random_i32()) >> 31; + expected_g = (actual_g = random_i32()) >> 31; + expected_b = (actual_b = random_i32()) >> 31; + rgb.set(actual_a, actual_r, actual_g, actual_b); + rgb.sra(rgbaint_t(-16, -20, 46, 32)); + check_expected("rgbaint_t::sra"); + // test arithmetic shift right immediate (method) expected_a = (actual_a = random_i32()) >> 12; expected_r = (actual_r = random_i32()) >> 12; @@ -917,6 +962,15 @@ void validate_rgb() rgb.sra_imm(9); check_expected("rgbaint_t::sra_imm"); + // test arithmetic shift right immediate out of range (method) + expected_a = (actual_a = random_i32()) >> 31; + expected_r = (actual_r = random_i32()) >> 31; + expected_g = (actual_g = random_i32()) >> 31; + expected_b = (actual_b = random_i32()) >> 31; + rgb.set(actual_a, actual_r, actual_g, actual_b); + rgb.sra_imm(38); + check_expected("rgbaint_t::sra_imm"); + // test arithmetic shift right immediate (operator) expected_a = (actual_a = random_i32()) >> 7; expected_r = (actual_r = random_i32()) >> 7; @@ -935,6 +989,15 @@ void validate_rgb() rgb >>= 11; check_expected("rgbaint_t::operator>>="); + // test arithmetic shift right immediate out of range (operator) + expected_a = (actual_a = random_i32()) >> 31; + expected_r = (actual_r = random_i32()) >> 31; + expected_g = (actual_g = random_i32()) >> 31; + expected_b = (actual_b = random_i32()) >> 31; + rgb.set(actual_a, actual_r, actual_g, actual_b); + rgb >>= 41; + check_expected("rgbaint_t::operator>>="); + // test RGB equality comparison actual_a = random_i32_nolimit(); actual_r = random_i32_nolimit(); diff --git a/src/emu/video/rgbgen.h b/src/emu/video/rgbgen.h index e460208d9fd..b20d79c94d8 100644 --- a/src/emu/video/rgbgen.h +++ b/src/emu/video/rgbgen.h @@ -151,16 +151,21 @@ public: inline void shl(const rgbaint_t& shift) { - m_a <<= shift.m_a; - m_r <<= shift.m_r; - m_g <<= shift.m_g; - m_b <<= shift.m_b; + m_a = (u32(shift.m_a) > 31) ? 0 : (m_a << shift.m_a); + m_r = (u32(shift.m_r) > 31) ? 0 : (m_r << shift.m_r); + m_g = (u32(shift.m_g) > 31) ? 0 : (m_g << shift.m_g); + m_b = (u32(shift.m_b) > 31) ? 0 : (m_b << shift.m_b); } inline void shl_imm(const u8 shift) { if (shift == 0) return; + if (shift > 31) + { + zero(); + return; + } m_a <<= shift; m_r <<= shift; @@ -170,16 +175,21 @@ public: inline void shr(const rgbaint_t& shift) { - m_a = s32(u32(m_a) >> shift.m_a); - m_r = s32(u32(m_r) >> shift.m_r); - m_g = s32(u32(m_g) >> shift.m_g); - m_b = s32(u32(m_b) >> shift.m_b); + m_a = (u32(shift.m_a) > 31) ? 0 : s32(u32(m_a) >> shift.m_a); + m_r = (u32(shift.m_r) > 31) ? 0 : s32(u32(m_r) >> shift.m_r); + m_g = (u32(shift.m_g) > 31) ? 0 : s32(u32(m_g) >> shift.m_g); + m_b = (u32(shift.m_b) > 31) ? 0 : s32(u32(m_b) >> shift.m_b); } inline void shr_imm(const u8 shift) { if (shift == 0) return; + if (shift > 31) + { + zero(); + return; + } m_a = s32(u32(m_a) >> shift); m_r = s32(u32(m_r) >> shift); @@ -189,43 +199,19 @@ public: inline void sra(const rgbaint_t& shift) { - m_a >>= shift.m_a; - if (m_a & (1 << (31 - shift.m_a))) - m_a |= ~0 << (32 - shift.m_a); - - m_r >>= shift.m_r; - if (m_r & (1 << (31 - shift.m_r))) - m_r |= ~0 << (32 - shift.m_r); - - m_g >>= shift.m_g; - if (m_g & (1 << (31 - shift.m_g))) - m_g |= ~0 << (32 - shift.m_g); - - m_b >>= shift.m_b; - if (m_b & (1 << (31 - shift.m_b))) - m_b |= ~0 << (32 - shift.m_b); + m_a >>= (u32(shift.m_a) > 31) ? 31 : shift.m_a; + m_r >>= (u32(shift.m_r) > 31) ? 31 : shift.m_r; + m_g >>= (u32(shift.m_g) > 31) ? 31 : shift.m_g; + m_b >>= (u32(shift.m_b) > 31) ? 31 : shift.m_b; } inline void sra_imm(const u8 shift) { - const u32 high_bit = 1 << (31 - shift); - const u32 high_mask = ~0 << (32 - shift); - - m_a >>= shift; - if (m_a & high_bit) - m_a |= high_mask; - - m_r >>= shift; - if (m_r & high_bit) - m_r |= high_mask; - - m_g >>= shift; - if (m_g & high_bit) - m_g |= high_mask; - - m_b >>= shift; - if (m_b & high_bit) - m_b |= high_mask; + const u8 s = std::min(shift, 31); + m_a >>= s; + m_r >>= s; + m_g >>= s; + m_b >>= s; } void or_reg(const rgbaint_t& color) { or_imm_rgba(color.m_a, color.m_r, color.m_g, color.m_b); } -- cgit v1.2.3