mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-25 18:05:12 -04:00
Restore BPE FMV cutover fix and SIMD MDEC paths.
Only re-arm depth24 cutover blank on long MDEC idle (not every ~15fps decode gap), and bring back SSE2/NEON IDCT hot paths lost from the dirty tree. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+13
-6
@@ -427,8 +427,9 @@ static int s_fmv_skip_present_skip = 0;
|
||||
static int s_netplay_depth24_present_skip = 0;
|
||||
static uint32_t s_fmv_skip_last_mdec = 0;
|
||||
static int s_fmv_skip_hold = 0;
|
||||
/* MotK FMV cutover: after an idle gap, blank the first depth24+MDEC presents
|
||||
* so one-frame RGB888 junk (stale VRAM) never reaches the window. */
|
||||
/* MotK FMV cutover: after leaving depth24 (or a long MDEC idle), blank the
|
||||
* first depth24+MDEC presents so one-frame RGB888 junk never reaches the
|
||||
* window. Short inter-frame MDEC gaps must not re-arm this (see cutover_tick). */
|
||||
static int s_d24_prev_mdec = 0;
|
||||
static int s_d24_saw_gap = 0;
|
||||
static int s_d24_cutover_blank = 0;
|
||||
@@ -3681,16 +3682,22 @@ static void load_transition_note(int read_active, int load_active,
|
||||
}
|
||||
|
||||
/* Tick MotK-style depth24 cutover state once per present. Arm a short full-
|
||||
* frame blank when MDEC returns after an idle gap (or after leaving depth24). */
|
||||
* frame blank when MDEC returns after leaving depth24, or after a *long*
|
||||
* intra-depth24 idle (real inter-movie gap) — not after every short gap
|
||||
* between ~15fps MDEC frames. With SIMD IDCT a movie frame often finishes in
|
||||
* one vblank; treating !mdec_recently_active(3) as a cutover re-armed a
|
||||
* 2-present full black blank on every decode burst (BPE FMV flicker). */
|
||||
static void depth24_cutover_tick(int depth24) {
|
||||
const int mdec_on = depth24 && mdec_recently_active(3);
|
||||
/* ~0.5s @60Hz — longer than inter-frame MDEC idle in a live movie. */
|
||||
const int mdec_long_idle = depth24 && !mdec_recently_active(30);
|
||||
if (!depth24) {
|
||||
s_d24_prev_mdec = 0;
|
||||
s_d24_cutover_blank = 0;
|
||||
s_d24_saw_gap = 1; /* next depth24+MDEC is a fresh movie cutover */
|
||||
return;
|
||||
}
|
||||
if (!mdec_on)
|
||||
if (mdec_long_idle)
|
||||
s_d24_saw_gap = 1;
|
||||
if (s_d24_saw_gap && mdec_on && !s_d24_prev_mdec) {
|
||||
/* Hide the transitional present(s) that still show stale RGB888 junk. */
|
||||
@@ -3710,8 +3717,8 @@ static void depth24_cutover_tick(int depth24) {
|
||||
* reset the span — hold ticks skip Swap, then the next present saw lim=0
|
||||
* and wiped the whole frame every vblank.
|
||||
*
|
||||
* Optional short cutover blank (tip): full-frame black for 1–2 presents when
|
||||
* MDEC returns after an idle gap, hiding one-frame transitional junk. */
|
||||
* Optional short cutover blank: full-frame black for 1–2 presents on movie
|
||||
* start / long idle resume only (see depth24_cutover_tick). */
|
||||
static void depth24_fix_trailing_margin(uint32_t *buf, uint32_t w, uint32_t h,
|
||||
uint32_t display_x) {
|
||||
if (!buf || w < 8u || h == 0u) return;
|
||||
|
||||
+321
-41
@@ -5,6 +5,22 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* x86-64 always has SSE2; MSVC x64 does not define __SSE2__. */
|
||||
#if defined(__SSE2__) || defined(_M_X64) || defined(_M_AMD64) || \
|
||||
(defined(_M_IX86_FP) && _M_IX86_FP >= 2)
|
||||
#include <emmintrin.h>
|
||||
#define MDEC_HAVE_SSE2 1
|
||||
#if defined(_MSC_VER)
|
||||
#define MDEC_ALIGN16 __declspec(align(16))
|
||||
#else
|
||||
#define MDEC_ALIGN16 __attribute__((aligned(16)))
|
||||
#endif
|
||||
#endif
|
||||
#if !defined(MDEC_HAVE_SSE2) && (defined(__ARM_NEON) || defined(__ARM_NEON__))
|
||||
#include <arm_neon.h>
|
||||
#define MDEC_HAVE_NEON 1
|
||||
#endif
|
||||
|
||||
extern uint64_t s_frame_count;
|
||||
|
||||
/* FMV-activity detector: frame stamp of the newest colour (15/24-bit) MDEC
|
||||
@@ -232,73 +248,172 @@ static int mask9_clamp_s8(int v) {
|
||||
return v;
|
||||
}
|
||||
|
||||
/* Faithful R3000A MDEC IDCT (Beetle IDCT/IDCT_1D_Multi, mdec.cpp:243-291).
|
||||
* Two separable 1-D passes over the >>3 scale matrix: pass 1 keeps int16 and
|
||||
* transposes (out[x*8+col]); pass 2 clamps to int8 via Mask9ClampS8. Rounding
|
||||
* is (sum + 0x4000) >> 15 (vs the old (sum+0xFFF)/0x2000 + per-tap /8, whose
|
||||
* bias differed from hardware → the washed/wrong-contrast FMV). The block buffer
|
||||
* holds int8-range samples on return. */
|
||||
static void idct_block(int16_t *block) {
|
||||
/* DC-only fast path: bit-identical to the loops below when AC is zero
|
||||
* (common in dark/flat FMV macroblocks). Pass1 only fills tmp[*][0];
|
||||
* pass2 only multiplies by scale[*][0]. */
|
||||
/* Faithful R3000A MDEC IDCT (Beetle IDCT/IDCT_1D_Multi). Two separable 1-D
|
||||
* passes over the >>3 scale matrix: pass 1 keeps int16 and transposes
|
||||
* (out[x*8+col]); pass 2 clamps via Mask9ClampS8. Rounding (sum+0x4000)>>15.
|
||||
* SSE2 path matches Beetle's madd_epi16 reduce (bit-identical to scalar). */
|
||||
|
||||
static void idct_block_dc_only(int16_t *block)
|
||||
{
|
||||
int16_t tmp0[8];
|
||||
int dc = block[0];
|
||||
int x, col;
|
||||
for (x = 0; x < 8; x++) {
|
||||
int sum = dc * (int)mdec.scale[x * 8];
|
||||
tmp0[x] = (int16_t)((sum + 0x4000) >> 15);
|
||||
}
|
||||
for (col = 0; col < 8; col++) {
|
||||
for (x = 0; x < 8; x++) {
|
||||
int sum = (int)tmp0[col] * (int)mdec.scale[x * 8];
|
||||
block[col * 8 + x] =
|
||||
(int16_t)mask9_clamp_s8((sum + 0x4000) >> 15);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void idct_block_scalar(int16_t *block)
|
||||
{
|
||||
int ac = 0;
|
||||
for (int i = 1; i < 64; i++) ac |= block[i];
|
||||
int i, col, x, u;
|
||||
int16_t tmp[64];
|
||||
|
||||
for (i = 1; i < 64; i++)
|
||||
ac |= block[i];
|
||||
if (!ac) {
|
||||
int16_t tmp0[8];
|
||||
int dc = block[0];
|
||||
for (int x = 0; x < 8; x++) {
|
||||
int sum = dc * (int)mdec.scale[x * 8];
|
||||
tmp0[x] = (int16_t)((sum + 0x4000) >> 15);
|
||||
}
|
||||
for (int col = 0; col < 8; col++) {
|
||||
for (int x = 0; x < 8; x++) {
|
||||
int sum = (int)tmp0[col] * (int)mdec.scale[x * 8];
|
||||
block[col * 8 + x] =
|
||||
(int16_t)mask9_clamp_s8((sum + 0x4000) >> 15);
|
||||
}
|
||||
}
|
||||
idct_block_dc_only(block);
|
||||
return;
|
||||
}
|
||||
|
||||
int16_t tmp[64];
|
||||
/* pass 1 — int16 out, transposed. Skip all-zero source columns
|
||||
* (sparse AC after zig-zag); zero column ⇒ zero tmp[*][col]. */
|
||||
for (int col = 0; col < 8; col++) {
|
||||
for (col = 0; col < 8; col++) {
|
||||
const int16_t *src = block + col * 8;
|
||||
int col_or = (int)src[0] | (int)src[1] | (int)src[2] | (int)src[3]
|
||||
| (int)src[4] | (int)src[5] | (int)src[6] | (int)src[7];
|
||||
int col_or = (int)src[0] | (int)src[1] | (int)src[2] | (int)src[3] |
|
||||
(int)src[4] | (int)src[5] | (int)src[6] | (int)src[7];
|
||||
if (!col_or) {
|
||||
for (int x = 0; x < 8; x++) tmp[x * 8 + col] = 0;
|
||||
for (x = 0; x < 8; x++)
|
||||
tmp[x * 8 + col] = 0;
|
||||
continue;
|
||||
}
|
||||
for (int x = 0; x < 8; x++) {
|
||||
for (x = 0; x < 8; x++) {
|
||||
int sum = 0;
|
||||
const int16_t *sc = mdec.scale + x * 8;
|
||||
for (int u = 0; u < 8; u++)
|
||||
for (u = 0; u < 8; u++)
|
||||
sum += (int)src[u] * (int)sc[u];
|
||||
tmp[x * 8 + col] = (int16_t)((sum + 0x4000) >> 15);
|
||||
}
|
||||
}
|
||||
/* pass 2 — int8 out (Mask9ClampS8), no transpose. Same zero-row skip. */
|
||||
for (int col = 0; col < 8; col++) {
|
||||
for (col = 0; col < 8; col++) {
|
||||
const int16_t *src = tmp + col * 8;
|
||||
int col_or = (int)src[0] | (int)src[1] | (int)src[2] | (int)src[3]
|
||||
| (int)src[4] | (int)src[5] | (int)src[6] | (int)src[7];
|
||||
int col_or = (int)src[0] | (int)src[1] | (int)src[2] | (int)src[3] |
|
||||
(int)src[4] | (int)src[5] | (int)src[6] | (int)src[7];
|
||||
if (!col_or) {
|
||||
for (int x = 0; x < 8; x++) block[col * 8 + x] = 0;
|
||||
for (x = 0; x < 8; x++)
|
||||
block[col * 8 + x] = 0;
|
||||
continue;
|
||||
}
|
||||
for (int x = 0; x < 8; x++) {
|
||||
for (x = 0; x < 8; x++) {
|
||||
int sum = 0;
|
||||
const int16_t *sc = mdec.scale + x * 8;
|
||||
for (int u = 0; u < 8; u++)
|
||||
for (u = 0; u < 8; u++)
|
||||
sum += (int)src[u] * (int)sc[u];
|
||||
block[col * 8 + x] = (int16_t)mask9_clamp_s8((sum + 0x4000) >> 15);
|
||||
block[col * 8 + x] =
|
||||
(int16_t)mask9_clamp_s8((sum + 0x4000) >> 15);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(MDEC_HAVE_SSE2)
|
||||
/* Horizontal sum of 4×i32 after madd_epi16 — same reduce as Beetle mdec.c. */
|
||||
static int idct_sse2_dot8(const int16_t *src8, const int16_t *scale8)
|
||||
{
|
||||
__m128i c = _mm_loadu_si128((const __m128i *)src8);
|
||||
__m128i m = _mm_loadu_si128((const __m128i *)scale8);
|
||||
__m128i sum = _mm_madd_epi16(m, c);
|
||||
MDEC_ALIGN16 int32_t tmp[4];
|
||||
sum = _mm_add_epi32(sum, _mm_shuffle_epi32(sum, _MM_SHUFFLE(0, 1, 2, 3)));
|
||||
sum = _mm_add_epi32(sum, _mm_shuffle_epi32(sum, _MM_SHUFFLE(0, 0, 0, 1)));
|
||||
_mm_store_si128((__m128i *)tmp, sum);
|
||||
return tmp[0];
|
||||
}
|
||||
|
||||
static void idct_block_sse2(int16_t *block)
|
||||
{
|
||||
int ac = 0;
|
||||
int i, col, x;
|
||||
MDEC_ALIGN16 int16_t tmp[64];
|
||||
|
||||
for (i = 1; i < 64; i++)
|
||||
ac |= block[i];
|
||||
if (!ac) {
|
||||
idct_block_dc_only(block);
|
||||
return;
|
||||
}
|
||||
|
||||
for (col = 0; col < 8; col++) {
|
||||
const int16_t *src = block + col * 8;
|
||||
int col_or = (int)src[0] | (int)src[1] | (int)src[2] | (int)src[3] |
|
||||
(int)src[4] | (int)src[5] | (int)src[6] | (int)src[7];
|
||||
if (!col_or) {
|
||||
for (x = 0; x < 8; x++)
|
||||
tmp[x * 8 + col] = 0;
|
||||
continue;
|
||||
}
|
||||
for (x = 0; x < 8; x++) {
|
||||
int sum = idct_sse2_dot8(src, mdec.scale + x * 8);
|
||||
tmp[x * 8 + col] = (int16_t)((sum + 0x4000) >> 15);
|
||||
}
|
||||
}
|
||||
for (col = 0; col < 8; col++) {
|
||||
const int16_t *src = tmp + col * 8;
|
||||
int col_or = (int)src[0] | (int)src[1] | (int)src[2] | (int)src[3] |
|
||||
(int)src[4] | (int)src[5] | (int)src[6] | (int)src[7];
|
||||
if (!col_or) {
|
||||
for (x = 0; x < 8; x++)
|
||||
block[col * 8 + x] = 0;
|
||||
continue;
|
||||
}
|
||||
for (x = 0; x < 8; x++) {
|
||||
int sum = idct_sse2_dot8(src, mdec.scale + x * 8);
|
||||
block[col * 8 + x] =
|
||||
(int16_t)mask9_clamp_s8((sum + 0x4000) >> 15);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void idct_simd_selfcheck(void)
|
||||
{
|
||||
uint32_t seed = 0xC0FFEEu;
|
||||
int n;
|
||||
for (n = 0; n < 64; n++)
|
||||
mdec.scale[n] = (int16_t)(((n % 9) - 4) * 256);
|
||||
/* Deterministic patterns + PRNG — abort if SSE2 ever drifts from scalar. */
|
||||
for (n = 0; n < 512; n++) {
|
||||
int16_t a[64], b[64];
|
||||
int i;
|
||||
for (i = 0; i < 64; i++) {
|
||||
seed = seed * 1664525u + 1013904223u;
|
||||
a[i] = (int16_t)((int)(seed >> 16) - 32768);
|
||||
if (n < 8)
|
||||
a[i] = (i == 0) ? (int16_t)(n * 100) : 0; /* DC-only */
|
||||
b[i] = a[i];
|
||||
}
|
||||
idct_block_scalar(a);
|
||||
idct_block_sse2(b);
|
||||
if (memcmp(a, b, sizeof(a)) != 0)
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void idct_block(int16_t *block)
|
||||
{
|
||||
idct_block_sse2(block);
|
||||
}
|
||||
#else
|
||||
static void idct_block(int16_t *block)
|
||||
{
|
||||
idct_block_scalar(block);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int decode_rle_block(int16_t *block, const uint8_t *quant,
|
||||
uint32_t *pos, uint32_t end) {
|
||||
memset(block, 0, 64 * sizeof(int16_t));
|
||||
@@ -395,6 +510,96 @@ static void append_luma_block(const int16_t *yblk) {
|
||||
mdec.output_size += 64u;
|
||||
}
|
||||
|
||||
#if defined(MDEC_HAVE_SSE2)
|
||||
/* Beetle mdec.c EncodeRow24 — 8 luma + 4 chroma → 24 RGB bytes, bit-exact. */
|
||||
#define MDEC_MUL32(a, b) \
|
||||
_mm_or_si128( \
|
||||
_mm_and_si128(_mm_mul_epu32((a), (b)), _mm_set1_epi64x(0xFFFFFFFFull)),\
|
||||
_mm_slli_epi64( \
|
||||
_mm_mul_epu32(_mm_srli_epi64((a), 32), _mm_srli_epi64((b), 32)), \
|
||||
32))
|
||||
#define MDEC_M9(v) \
|
||||
_mm_min_epi16(_mm_max_epi16(_mm_srai_epi16(_mm_slli_epi16((v), 7), 7), \
|
||||
_mm_set1_epi16(-128)), \
|
||||
_mm_set1_epi16(127))
|
||||
|
||||
static void mdec_encode_row24_sse2(const int16_t *by, const int16_t *cb4,
|
||||
const int16_t *cr4, uint8_t rgb_xor,
|
||||
uint8_t *out)
|
||||
{
|
||||
int16_t cbd[8], crd[8];
|
||||
int8_t by8[8];
|
||||
int l, i;
|
||||
__m128i R, G, B;
|
||||
__m128i flip = _mm_set1_epi16((short)(0x80 ^ rgb_xor));
|
||||
uint8_t r8[8], g8[8], b8[8];
|
||||
__m128i y16, CB, CR, cb_lo, cb_hi, cr_lo, cr_hi, y_lo, y_hi;
|
||||
const __m128i k359 = _mm_set1_epi32(359);
|
||||
const __m128i k454 = _mm_set1_epi32(454);
|
||||
const __m128i km88 = _mm_set1_epi32(-88);
|
||||
const __m128i km183 = _mm_set1_epi32(-183);
|
||||
const __m128i bias = _mm_set1_epi32(0x80);
|
||||
__m128i r_lo, r_hi, b_lo, b_hi, a0, a1, c0, c1, g_lo, g_hi;
|
||||
|
||||
for (l = 0; l < 8; l++)
|
||||
by8[l] = (int8_t)by[l];
|
||||
for (l = 0; l < 4; l++) {
|
||||
cbd[2 * l] = cbd[2 * l + 1] = (int16_t)cb4[l];
|
||||
crd[2 * l] = crd[2 * l + 1] = (int16_t)cr4[l];
|
||||
}
|
||||
|
||||
y16 = _mm_srai_epi16(
|
||||
_mm_slli_epi16(
|
||||
_mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)by8),
|
||||
_mm_setzero_si128()),
|
||||
8),
|
||||
8);
|
||||
CB = _mm_loadu_si128((const __m128i *)cbd);
|
||||
CR = _mm_loadu_si128((const __m128i *)crd);
|
||||
cb_lo = _mm_srai_epi32(_mm_unpacklo_epi16(CB, CB), 16);
|
||||
cb_hi = _mm_srai_epi32(_mm_unpackhi_epi16(CB, CB), 16);
|
||||
cr_lo = _mm_srai_epi32(_mm_unpacklo_epi16(CR, CR), 16);
|
||||
cr_hi = _mm_srai_epi32(_mm_unpackhi_epi16(CR, CR), 16);
|
||||
y_lo = _mm_srai_epi32(_mm_unpacklo_epi16(y16, y16), 16);
|
||||
y_hi = _mm_srai_epi32(_mm_unpackhi_epi16(y16, y16), 16);
|
||||
|
||||
r_lo = _mm_add_epi32(
|
||||
y_lo, _mm_srai_epi32(_mm_add_epi32(MDEC_MUL32(k359, cr_lo), bias), 8));
|
||||
r_hi = _mm_add_epi32(
|
||||
y_hi, _mm_srai_epi32(_mm_add_epi32(MDEC_MUL32(k359, cr_hi), bias), 8));
|
||||
b_lo = _mm_add_epi32(
|
||||
y_lo, _mm_srai_epi32(_mm_add_epi32(MDEC_MUL32(k454, cb_lo), bias), 8));
|
||||
b_hi = _mm_add_epi32(
|
||||
y_hi, _mm_srai_epi32(_mm_add_epi32(MDEC_MUL32(k454, cb_hi), bias), 8));
|
||||
a0 = _mm_andnot_si128(_mm_set1_epi32(0x1F), MDEC_MUL32(km88, cb_lo));
|
||||
a1 = _mm_andnot_si128(_mm_set1_epi32(0x1F), MDEC_MUL32(km88, cb_hi));
|
||||
c0 = _mm_andnot_si128(_mm_set1_epi32(0x07), MDEC_MUL32(km183, cr_lo));
|
||||
c1 = _mm_andnot_si128(_mm_set1_epi32(0x07), MDEC_MUL32(km183, cr_hi));
|
||||
g_lo = _mm_add_epi32(
|
||||
y_lo,
|
||||
_mm_srai_epi32(_mm_add_epi32(_mm_add_epi32(a0, c0), bias), 8));
|
||||
g_hi = _mm_add_epi32(
|
||||
y_hi,
|
||||
_mm_srai_epi32(_mm_add_epi32(_mm_add_epi32(a1, c1), bias), 8));
|
||||
R = MDEC_M9(_mm_packs_epi32(r_lo, r_hi));
|
||||
G = MDEC_M9(_mm_packs_epi32(g_lo, g_hi));
|
||||
B = MDEC_M9(_mm_packs_epi32(b_lo, b_hi));
|
||||
R = _mm_xor_si128(_mm_and_si128(R, _mm_set1_epi16(0xFF)), flip);
|
||||
G = _mm_xor_si128(_mm_and_si128(G, _mm_set1_epi16(0xFF)), flip);
|
||||
B = _mm_xor_si128(_mm_and_si128(B, _mm_set1_epi16(0xFF)), flip);
|
||||
_mm_storel_epi64((__m128i *)r8, _mm_packus_epi16(R, R));
|
||||
_mm_storel_epi64((__m128i *)g8, _mm_packus_epi16(G, G));
|
||||
_mm_storel_epi64((__m128i *)b8, _mm_packus_epi16(B, B));
|
||||
for (i = 0; i < 8; i++) {
|
||||
out[i * 3 + 0] = r8[i];
|
||||
out[i * 3 + 1] = g8[i];
|
||||
out[i * 3 + 2] = b8[i];
|
||||
}
|
||||
}
|
||||
#undef MDEC_MUL32
|
||||
#undef MDEC_M9
|
||||
#endif /* MDEC_HAVE_SSE2 */
|
||||
|
||||
static void append_color_macroblock(const int16_t *crblk, const int16_t *cbblk,
|
||||
const int16_t yblk[4][64]) {
|
||||
/* 16×16: 512 bytes @15bpp, 768 @24bpp — reserve once per MB. */
|
||||
@@ -402,6 +607,27 @@ static void append_color_macroblock(const int16_t *crblk, const int16_t *cbblk,
|
||||
uint8_t *out = output_reserve(need);
|
||||
if (!out) return;
|
||||
uint8_t *p = out;
|
||||
#if defined(MDEC_HAVE_SSE2)
|
||||
/* 24bpp FMV path — row SIMD (Beetle EncodeRow24). 16bpp stays scalar. */
|
||||
if (mdec.output_depth != 3) {
|
||||
uint8_t rgb_xor = mdec.output_signed ? 0x80u : 0x00u;
|
||||
int py;
|
||||
for (py = 0; py < 16; py++) {
|
||||
int y_left = (py >= 8 ? 2 : 0);
|
||||
int y_right = y_left + 1;
|
||||
int ly = py & 7;
|
||||
int crow = (py >> 1) * 8;
|
||||
mdec_encode_row24_sse2(&yblk[y_left][ly * 8], &cbblk[crow],
|
||||
&crblk[crow], rgb_xor, p);
|
||||
p += 24;
|
||||
mdec_encode_row24_sse2(&yblk[y_right][ly * 8], &cbblk[crow + 4],
|
||||
&crblk[crow + 4], rgb_xor, p);
|
||||
p += 24;
|
||||
}
|
||||
mdec.output_size += need;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
for (int py = 0; py < 16; py++) {
|
||||
for (int px = 0; px < 16; px++) {
|
||||
int y_index = (py >= 8 ? 2 : 0) + (px >= 8 ? 1 : 0);
|
||||
@@ -562,6 +788,60 @@ void mdec_init(void) {
|
||||
}
|
||||
mdec.output_depth = 3;
|
||||
mdec.current_block = 4;
|
||||
#if defined(MDEC_HAVE_SSE2)
|
||||
idct_simd_selfcheck();
|
||||
memset(mdec.scale, 0, sizeof(mdec.scale));
|
||||
/* YCbCr row vs scalar emit — 24bpp FMV path (depth 2). */
|
||||
{
|
||||
uint32_t seed = 0xBADC0DEEu;
|
||||
int n, i;
|
||||
mdec.output_depth = 2;
|
||||
mdec.output_signed = 0;
|
||||
for (n = 0; n < 256; n++) {
|
||||
int16_t by[8], cb4[4], cr4[4];
|
||||
uint8_t sse[24], ref[24];
|
||||
uint8_t *rp = ref;
|
||||
for (i = 0; i < 8; i++) {
|
||||
seed = seed * 1664525u + 1013904223u;
|
||||
by[i] = (int16_t)((int)(seed % 255u) - 128);
|
||||
}
|
||||
for (i = 0; i < 4; i++) {
|
||||
seed = seed * 1664525u + 1013904223u;
|
||||
cb4[i] = (int16_t)((int)(seed % 255u) - 128);
|
||||
seed = seed * 1664525u + 1013904223u;
|
||||
cr4[i] = (int16_t)((int)(seed % 255u) - 128);
|
||||
}
|
||||
mdec_encode_row24_sse2(by, cb4, cr4, 0, sse);
|
||||
for (i = 0; i < 8; i++)
|
||||
rp = emit_rgb_pixel(rp, by[i], cr4[i >> 1], cb4[i >> 1]);
|
||||
if (memcmp(sse, ref, 24) != 0)
|
||||
abort();
|
||||
}
|
||||
mdec.output_signed = 1;
|
||||
for (n = 0; n < 64; n++) {
|
||||
int16_t by[8], cb4[4], cr4[4];
|
||||
uint8_t sse[24], ref[24];
|
||||
uint8_t *rp = ref;
|
||||
for (i = 0; i < 8; i++) {
|
||||
seed = seed * 1664525u + 1013904223u;
|
||||
by[i] = (int16_t)((int)(seed % 255u) - 128);
|
||||
}
|
||||
for (i = 0; i < 4; i++) {
|
||||
seed = seed * 1664525u + 1013904223u;
|
||||
cb4[i] = (int16_t)((int)(seed % 255u) - 128);
|
||||
seed = seed * 1664525u + 1013904223u;
|
||||
cr4[i] = (int16_t)((int)(seed % 255u) - 128);
|
||||
}
|
||||
mdec_encode_row24_sse2(by, cb4, cr4, 0x80u, sse);
|
||||
for (i = 0; i < 8; i++)
|
||||
rp = emit_rgb_pixel(rp, by[i], cr4[i >> 1], cb4[i >> 1]);
|
||||
if (memcmp(sse, ref, 24) != 0)
|
||||
abort();
|
||||
}
|
||||
mdec.output_signed = 0;
|
||||
mdec.output_depth = 3;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t mdec_read(uint32_t addr) {
|
||||
|
||||
Reference in New Issue
Block a user