Merge pull request #3754 from akallabeth/asm3

NEON and SSSE3 decoder optimisations
This commit is contained in:
Martin Fleisz 2017-02-14 09:23:21 +01:00 committed by GitHub
commit e97c4b57a4
14 changed files with 2295 additions and 623 deletions

View File

@ -103,35 +103,14 @@ static BOOL convert_color(BYTE* dst, UINT32 nDstStep, UINT32 DstFormat,
const BYTE* src, UINT32 nSrcStep, UINT32 SrcFormat,
UINT32 nDstWidth, UINT32 nDstHeight, const gdiPalette* palette)
{
UINT32 x, y;
if (nWidth + nXDst > nDstWidth)
nWidth = nDstWidth - nXDst;
if (nHeight + nYDst > nDstHeight)
nHeight = nDstHeight - nYDst;
for (y = 0; y < nHeight; y++)
{
const BYTE* pSrcLine = &src[y * nSrcStep];
BYTE* pDstLine = &dst[(nYDst + y) * nDstStep];
for (x = 0; x < nWidth; x++)
{
const BYTE* pSrcPixel =
&pSrcLine[x * GetBytesPerPixel(SrcFormat)];
BYTE* pDstPixel =
&pDstLine[(nXDst + x) * GetBytesPerPixel(DstFormat)];
UINT32 color = ReadColor(pSrcPixel, SrcFormat);
color = ConvertColor(color, SrcFormat,
DstFormat, palette);
if (!WriteColor(pDstPixel, DstFormat, color))
return FALSE;
}
}
return TRUE;
return freerdp_image_copy(dst, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight,
src, SrcFormat, nSrcStep, 0, 0, palette, 0);
}
static BOOL clear_decompress_nscodec(NSC_CONTEXT* nsc, UINT32 width,

View File

@ -847,7 +847,7 @@ static void openh264_trace_callback(H264_CONTEXT* h264, int level,
WLog_INFO(TAG, "%d - %s", level, message);
}
static int openh264_decompress(H264_CONTEXT* h264, BYTE* pSrcData,
static int openh264_decompress(H264_CONTEXT* h264, const BYTE* pSrcData,
UINT32 SrcSize, UINT32 plane)
{
DECODING_STATE state;
@ -1607,13 +1607,12 @@ INT32 avc444_compress(H264_CONTEXT* h264, const BYTE* pSrcData, DWORD SrcFormat,
}
static BOOL avc444_process_rect(H264_CONTEXT* h264,
const RECTANGLE_16* rect,
UINT32 nDstWidth, UINT32 nDstHeight,
BOOL main, BOOL aux)
const RECTANGLE_16* mainRects, UINT32 nrMainRects,
const RECTANGLE_16* auxRects, UINT32 nrAuxRects)
{
const primitives_t* prims = primitives_get();
prim_size_t roi;
UINT16 width, height;
UINT32 x;
const BYTE* pYUVMainPoint[3] = { NULL, NULL, NULL };
const BYTE* pYUVAuxPoint[3] = { NULL, NULL, NULL };
BYTE* pYUVDstPoint[3];
@ -1624,74 +1623,77 @@ static BOOL avc444_process_rect(H264_CONTEXT* h264,
BYTE** ppYUVAuxData = h264->pYUVData[1];
BYTE** ppYUVMainData = h264->pYUVData[0];
if (!check_rect(h264, rect, nDstWidth, nDstHeight))
return FALSE;
width = rect->right - rect->left + 1;
height = rect->bottom - rect->top + 1;
roi.width = width;
roi.height = height;
if (main)
for (x = 0; x < nrMainRects; x++)
{
const RECTANGLE_16* rect = &mainRects[x];
prim_size_t roi;
if (!check_rect(h264, rect, nDstWidth, nDstHeight))
continue;
pYUVMainPoint[0] = ppYUVMainData[0] + rect->top * piMainStride[0] +
rect->left;
pYUVMainPoint[1] = ppYUVMainData[1] + rect->top / 2 * piMainStride[1] +
rect->left / 2;
pYUVMainPoint[2] = ppYUVMainData[2] + rect->top / 2 * piMainStride[2] +
rect->left / 2;
pYUVDstPoint[0] = ppYUVDstData[0] + rect->top * piDstStride[0] +
rect->left;
pYUVDstPoint[1] = ppYUVDstData[1] + rect->top * piDstStride[1] +
rect->left;
pYUVDstPoint[2] = ppYUVDstData[2] + rect->top * piDstStride[2] +
rect->left;
roi.width = rect->right - rect->left + 1;
roi.height = rect->bottom - rect->top + 1;
if (prims->YUV420CombineToYUV444(pYUVMainPoint, piMainStride,
NULL, NULL,
pYUVDstPoint, piDstStride,
&roi) != PRIMITIVES_SUCCESS)
return FALSE;
}
if (aux)
for (x = 0; x < nrAuxRects; x++)
{
const RECTANGLE_16* rect = &auxRects[x];
prim_size_t roi;
if (!check_rect(h264, rect, nDstWidth, nDstHeight))
continue;
pYUVAuxPoint[0] = ppYUVAuxData[0] + rect->top * piAuxStride[0] +
rect->left;
pYUVAuxPoint[1] = ppYUVAuxData[1] + rect->top / 2 * piAuxStride[1] +
rect->left / 2;
pYUVAuxPoint[2] = ppYUVAuxData[2] + rect->top / 2 * piAuxStride[2] +
rect->left / 2;
pYUVDstPoint[0] = ppYUVDstData[0] + rect->top * piDstStride[0] +
rect->left;
pYUVDstPoint[1] = ppYUVDstData[1] + rect->top * piDstStride[1] +
rect->left;
pYUVDstPoint[2] = ppYUVDstData[2] + rect->top * piDstStride[2] +
rect->left;
roi.width = rect->right - rect->left + 1;
roi.height = rect->bottom - rect->top + 1;
if (prims->YUV420CombineToYUV444(NULL, NULL,
pYUVAuxPoint, piAuxStride,
pYUVDstPoint, piDstStride,
&roi) != PRIMITIVES_SUCCESS)
return FALSE;
}
pYUVDstPoint[0] = ppYUVDstData[0] + rect->top * piDstStride[0] +
rect->left;
pYUVDstPoint[1] = ppYUVDstData[1] + rect->top * piDstStride[1] +
rect->left;
pYUVDstPoint[2] = ppYUVDstData[2] + rect->top * piDstStride[2] +
rect->left;
if (prims->YUV420CombineToYUV444(pYUVMainPoint, piMainStride,
pYUVAuxPoint, piAuxStride,
pYUVDstPoint, piDstStride,
&roi) != PRIMITIVES_SUCCESS)
return FALSE;
return TRUE;
}
static void avc444_rectangle_max(RECTANGLE_16* dst, const RECTANGLE_16* add)
{
if (dst->left > add->left)
dst->left = add->left;
if (dst->right < add->right)
dst->right = add->right;
if (dst->top > add->top)
dst->top = add->top;
if (dst->bottom < add->bottom)
dst->bottom = add->bottom;
}
static BOOL avc444_combine_yuv(H264_CONTEXT* h264,
const RECTANGLE_16* mainRegionRects,
UINT32 numMainRegionRect,
const RECTANGLE_16* auxRegionRects,
UINT32 numAuxRegionRect, UINT32 nDstWidth,
DWORD nDstHeight, UINT32 nDstStep)
DWORD nDstHeight)
{
UINT32 x;
RECTANGLE_16 rect;
const UINT32* piMainStride = h264->iStride[0];
UINT32* piDstSize = h264->iYUV444Size;
UINT32* piDstStride = h264->iYUV444Stride;
@ -1725,20 +1727,9 @@ static BOOL avc444_combine_yuv(H264_CONTEXT* h264,
}
}
rect.right = 0;
rect.bottom = 0;
rect.left = 0xFFFF;
rect.top = 0xFFFF;
for (x = 0; x < numMainRegionRect; x++)
avc444_rectangle_max(&rect, &mainRegionRects[x]);
for (x = 0; x < numAuxRegionRect; x++)
avc444_rectangle_max(&rect, &auxRegionRects[x]);
if (!avc444_process_rect(h264, &rect, nDstWidth, nDstHeight,
numMainRegionRect != 0,
numAuxRegionRect != 0))
if (!avc444_process_rect(h264, nDstWidth, nDstHeight,
mainRegionRects, numMainRegionRect,
auxRegionRects, numAuxRegionRect))
goto fail;
return TRUE;
@ -1846,20 +1837,20 @@ INT32 avc444_decompress(H264_CONTEXT* h264, BYTE op,
{
if (!avc444_combine_yuv(h264, yuvRects, numYuvRects,
chromaRects, numChromaRects,
nDstWidth, nDstHeight, nDstStep))
nDstWidth, nDstHeight))
status = -1002;
else
{
if (numYuvRects > 0)
{
if (!avc_yuv_to_rgb(h264, regionRects, numRegionRects, nDstWidth,
if (!avc_yuv_to_rgb(h264, yuvRects, numYuvRects, nDstWidth,
nDstHeight, nDstStep, pDstData, DstFormat, TRUE))
status = -1003;
}
if (numChromaRects > 0)
{
if (!avc_yuv_to_rgb(h264, auxRegionRects, numAuxRegionRect,
if (!avc_yuv_to_rgb(h264, chromaRects, numChromaRects,
nDstWidth, nDstHeight, nDstStep, pDstData,
DstFormat, TRUE))
status = -1004;

View File

@ -435,6 +435,134 @@ static pstatus_t ssse3_YCoCgRToRGB_8u_AC4R(
dstStep, width, height, shift, withAlpha);
}
}
#elif defined(WITH_NEON)
static pstatus_t neon_YCoCgToRGB_8u_X(
const BYTE* pSrc, INT32 srcStep,
BYTE* pDst, UINT32 DstFormat, INT32 dstStep,
UINT32 width, UINT32 height,
UINT8 shift, BYTE rPos, BYTE gPos, BYTE bPos, BYTE aPos, BOOL alpha)
{
UINT32 y;
BYTE* dptr = pDst;
const BYTE* sptr = pSrc;
const DWORD formatSize = GetBytesPerPixel(DstFormat);
const int8_t cll = shift - 1; /* -1 builds in the /2's */
const UINT32 srcPad = srcStep - (width * 4);
const UINT32 dstPad = dstStep - (width * formatSize);
const UINT32 pad = width % 8;
const uint8x8_t aVal = vdup_n_u8(0xFF);
const int8x8_t cllv = vdup_n_s8(cll);
for (y = 0; y < height; y++)
{
UINT32 x;
for (x = 0; x < width - pad; x += 8)
{
/* Note: shifts must be done before sign-conversion. */
const uint8x8x4_t raw = vld4_u8(sptr);
const int8x8_t CgRaw = vreinterpret_s8_u8(vshl_u8(raw.val[0], cllv));
const int8x8_t CoRaw = vreinterpret_s8_u8(vshl_u8(raw.val[1], cllv));
const int16x8_t Cg = vmovl_s8(CgRaw);
const int16x8_t Co = vmovl_s8(CoRaw);
const int16x8_t Y = vreinterpretq_s16_u16(vmovl_u8(raw.val[2])); /* UINT8 -> INT16 */
const int16x8_t T = vsubq_s16(Y, Cg);
const int16x8_t R = vaddq_s16(T, Co);
const int16x8_t G = vaddq_s16(Y, Cg);
const int16x8_t B = vsubq_s16(T, Co);
uint8x8x4_t bgrx;
bgrx.val[bPos] = vqmovun_s16(B);
bgrx.val[gPos] = vqmovun_s16(G);
bgrx.val[rPos] = vqmovun_s16(R);
if (alpha)
bgrx.val[aPos] = raw.val[3];
else
bgrx.val[aPos] = aVal;
vst4_u8(dptr, bgrx);
sptr += sizeof(raw);
dptr += sizeof(bgrx);
}
for (x = 0; x < pad; x++)
{
/* Note: shifts must be done before sign-conversion. */
const INT16 Cg = (INT16)((INT8)((*sptr++) << cll));
const INT16 Co = (INT16)((INT8)((*sptr++) << cll));
const INT16 Y = (INT16)(*sptr++); /* UINT8->INT16 */
const INT16 T = Y - Cg;
const INT16 R = T + Co;
const INT16 G = Y + Cg;
const INT16 B = T - Co;
BYTE bgra[4];
bgra[bPos] = CLIP(B);
bgra[gPos] = CLIP(G);
bgra[rPos] = CLIP(R);
bgra[aPos] = *sptr++;
if (!alpha)
bgra[aPos] = 0xFF;
*dptr++ = bgra[0];
*dptr++ = bgra[1];
*dptr++ = bgra[2];
*dptr++ = bgra[3];
}
sptr += srcPad;
dptr += dstPad;
}
return PRIMITIVES_SUCCESS;
}
static pstatus_t neon_YCoCgToRGB_8u_AC4R(
const BYTE* pSrc, INT32 srcStep,
BYTE* pDst, UINT32 DstFormat, INT32 dstStep,
UINT32 width, UINT32 height,
UINT8 shift,
BOOL withAlpha)
{
switch (DstFormat)
{
case PIXEL_FORMAT_BGRA32:
return neon_YCoCgToRGB_8u_X(pSrc, srcStep, pDst, DstFormat, dstStep, width, height, shift, 2, 1, 0,
3, withAlpha);
case PIXEL_FORMAT_BGRX32:
return neon_YCoCgToRGB_8u_X(pSrc, srcStep, pDst, DstFormat, dstStep, width, height, shift, 2, 1, 0,
3, withAlpha);
case PIXEL_FORMAT_RGBA32:
return neon_YCoCgToRGB_8u_X(pSrc, srcStep, pDst, DstFormat, dstStep, width, height, shift, 0, 1, 2,
3, withAlpha);
case PIXEL_FORMAT_RGBX32:
return neon_YCoCgToRGB_8u_X(pSrc, srcStep, pDst, DstFormat, dstStep, width, height, shift, 0, 1, 2,
3, withAlpha);
case PIXEL_FORMAT_ARGB32:
return neon_YCoCgToRGB_8u_X(pSrc, srcStep, pDst, DstFormat, dstStep, width, height, shift, 1, 2, 3,
0, withAlpha);
case PIXEL_FORMAT_XRGB32:
return neon_YCoCgToRGB_8u_X(pSrc, srcStep, pDst, DstFormat, dstStep, width, height, shift, 1, 2, 3,
0, withAlpha);
case PIXEL_FORMAT_ABGR32:
return neon_YCoCgToRGB_8u_X(pSrc, srcStep, pDst, DstFormat, dstStep, width, height, shift, 3, 2, 1,
0, withAlpha);
case PIXEL_FORMAT_XBGR32:
return neon_YCoCgToRGB_8u_X(pSrc, srcStep, pDst, DstFormat, dstStep, width, height, shift, 3, 2, 1,
0, withAlpha);
default:
return generic->YCoCgToRGB_8u_AC4R(pSrc, srcStep, pDst, DstFormat, dstStep, width, height, shift,
withAlpha);
}
}
#endif /* WITH_SSE2 */
/* ------------------------------------------------------------------------- */
@ -454,5 +582,12 @@ void primitives_init_YCoCg_opt(primitives_t* prims)
prims->YCoCgToRGB_8u_AC4R = ssse3_YCoCgRToRGB_8u_AC4R;
}
#elif defined(WITH_NEON)
if (IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE))
{
prims->YCoCgToRGB_8u_AC4R = neon_YCoCgToRGB_8u_AC4R;
}
#endif /* WITH_SSE2 */
}

View File

@ -280,47 +280,6 @@ static pstatus_t general_YUV444SplitToYUV420(
return PRIMITIVES_SUCCESS;
}
/**
* | R | ( | 256 0 403 | | Y | )
* | G | = ( | 256 -48 -120 | | U - 128 | ) >> 8
* | B | ( | 256 475 0 | | V - 128 | )
*/
static INLINE INT32 C(INT32 Y)
{
return (Y) - 0L;
}
static INLINE INT32 D(INT32 U)
{
return (U) - 128L;
}
static INLINE INT32 E(INT32 V)
{
return (V) - 128L;
}
static INLINE BYTE YUV2R(INT32 Y, INT32 U, INT32 V)
{
const INT32 r = (256L * C(Y) + 0L * D(U) + 403L * E(V));
const INT32 r8 = r >> 8L;
return CLIP(r8);
}
static INLINE BYTE YUV2G(INT32 Y, INT32 U, INT32 V)
{
const INT32 g = (256L * C(Y) - 48L * D(U) - 120L * E(V));
const INT32 g8 = g >> 8L;
return CLIP(g8);
}
static INLINE BYTE YUV2B(INT32 Y, INT32 U, INT32 V)
{
const INT32 b = (256L * C(Y) + 475L * D(U) + 0L * E(V));
const INT32 b8 = b >> 8L;
return CLIP(b8);
}
static pstatus_t general_YUV444ToRGB_8u_P3AC4R_general(
const BYTE* pSrc[3], const UINT32 srcStep[3],
BYTE* pDst, UINT32 dstStep, UINT32 DstFormat,
@ -343,8 +302,8 @@ static pstatus_t general_YUV444ToRGB_8u_P3AC4R_general(
for (x = 0; x < nWidth; x++)
{
const BYTE Y = pY[x];
const INT32 U = pU[x];
const INT32 V = pV[x];
const BYTE U = pU[x];
const BYTE V = pV[x];
const BYTE r = YUV2R(Y, U, V);
const BYTE g = YUV2G(Y, U, V);
const BYTE b = YUV2B(Y, U, V);
@ -376,8 +335,8 @@ static pstatus_t general_YUV444ToRGB_8u_P3AC4R_BGRX(
for (x = 0; x < nWidth; x++)
{
const BYTE Y = pY[x];
const INT32 U = pU[x];
const INT32 V = pV[x];
const BYTE U = pU[x];
const BYTE V = pV[x];
const BYTE r = YUV2R(Y, U, V);
const BYTE g = YUV2G(Y, U, V);
const BYTE b = YUV2B(Y, U, V);
@ -589,7 +548,7 @@ static INLINE pstatus_t general_RGBToYUV420_BGRX(
const BYTE* pSrc, UINT32 srcStep,
BYTE* pDst[3], UINT32 dstStep[3], const prim_size_t* roi)
{
UINT32 x, y, i, j;
UINT32 x, y, i;
size_t x1 = 0, x2 = 4, x3 = srcStep, x4 = srcStep + 4;
size_t y1 = 0, y2 = 1, y3 = dstStep[0], y4 = dstStep[0] + 1;
UINT32 max_x = roi->width - 1;
@ -606,7 +565,6 @@ static INLINE pstatus_t general_RGBToYUV420_BGRX(
{
BYTE R, G, B;
INT32 Ra, Ga, Ba;
UINT32 color;
/* row 1, pixel 1 */
Ba = B = *(src + x1 + 0);
Ga = G = *(src + x1 + 1);
@ -658,7 +616,7 @@ static INLINE pstatus_t general_RGBToYUV420_ANY(
BYTE* pDst[3], UINT32 dstStep[3], const prim_size_t* roi)
{
const UINT32 bpp = GetBytesPerPixel(srcFormat);
UINT32 x, y, i, j;
UINT32 x, y, i;
size_t x1 = 0, x2 = bpp, x3 = srcStep, x4 = srcStep + bpp;
size_t y1 = 0, y2 = 1, y3 = dstStep[0], y4 = dstStep[0] + 1;
UINT32 max_x = roi->width - 1;

View File

@ -31,22 +31,25 @@
#include "prim_internal.h"
static primitives_t* generic = NULL;
#ifdef WITH_SSE2
#include <emmintrin.h>
#include <tmmintrin.h>
#elif defined(WITH_NEON)
#include <arm_neon.h>
#endif /* WITH_SSE2 else WITH_NEON */
static primitives_t* generic = NULL;
#ifdef WITH_SSE2
/****************************************************************************/
/* SSSE3 YUV420 -> RGB conversion */
/****************************************************************************/
static pstatus_t ssse3_YUV420ToRGB_BGRX(
const BYTE** pSrc, const UINT32* srcStep,
BYTE* pDst, UINT32 dstStep, UINT32 dstFormat,
const prim_size_t* roi)
const BYTE** pSrc, const UINT32* srcStep,
BYTE* pDst, UINT32 dstStep, UINT32 dstFormat,
const prim_size_t* roi)
{
UINT32 lastRow, lastCol;
BYTE* UData, *VData, *YData;
@ -341,9 +344,9 @@ static pstatus_t ssse3_YUV420ToRGB_BGRX(
}
static pstatus_t ssse3_YUV420ToRGB(
const BYTE** pSrc, const UINT32* srcStep,
BYTE* pDst, UINT32 dstStep, UINT32 DstFormat,
const prim_size_t* roi)
const BYTE** pSrc, const UINT32* srcStep,
BYTE* pDst, UINT32 dstStep, UINT32 DstFormat,
const prim_size_t* roi)
{
switch (DstFormat)
{
@ -356,8 +359,115 @@ static pstatus_t ssse3_YUV420ToRGB(
}
}
static pstatus_t ssse3_YUV444ToRGB_8u_P3AC4R_BGRX(
const BYTE** pSrc, const UINT32* srcStep,
BYTE* pDst, UINT32 dstStep,
const prim_size_t* roi)
{
const UINT32 nWidth = roi->width;
const UINT32 nHeight = roi->height;
const __m128i c128 = _mm_set1_epi16(128);
const __m128i mapY = _mm_set_epi32(0x80800380, 0x80800280, 0x80800180, 0x80800080);
const __m128i map = _mm_set_epi32(0x80038002, 0x80018000, 0x80808080, 0x80808080);
UINT32 y;
for (y = 0; y < nHeight; y++)
{
UINT32 x;
__m128i* dst = (__m128i*)(pDst + dstStep * y);
const BYTE* YData = pSrc[0] + y * srcStep[0];
const BYTE* UData = pSrc[1] + y * srcStep[1];
const BYTE* VData = pSrc[2] + y * srcStep[2];
for (x = 0; x < nWidth; x += 4)
{
__m128i BGRX = _mm_set_epi32(0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000);
{
__m128i C, D, E;
/* Load Y values and expand to 32 bit */
{
const __m128i Yraw = _mm_loadu_si128((__m128i*)YData);
C = _mm_shuffle_epi8(Yraw, mapY); /* Reorder and multiply by 256 */
}
/* Load U values and expand to 32 bit */
{
const __m128i Uraw = _mm_loadu_si128((__m128i*)UData);
const __m128i U = _mm_shuffle_epi8(Uraw, map); /* Reorder dcba */
D = _mm_sub_epi16(U, c128); /* D = U - 128 */
}
/* Load V values and expand to 32 bit */
{
const __m128i Vraw = _mm_loadu_si128((__m128i*)VData);
const __m128i V = _mm_shuffle_epi8(Vraw, map); /* Reorder dcba */
E = _mm_sub_epi16(V, c128); /* E = V - 128 */
}
/* Get the R value */
{
const __m128i c403 = _mm_set1_epi16(403);
const __m128i e403 = _mm_unpackhi_epi16(_mm_mullo_epi16(E, c403), _mm_mulhi_epi16(E, c403));
const __m128i Rs = _mm_add_epi32(C, e403);
const __m128i R32 = _mm_srai_epi32(Rs, 8);
const __m128i R16 = _mm_packs_epi32(R32, _mm_setzero_si128());
const __m128i R = _mm_packus_epi16(R16, _mm_setzero_si128());
const __m128i mask = _mm_set_epi32(0x80038080, 0x80028080, 0x80018080, 0x80008080);
const __m128i packed = _mm_shuffle_epi8(R, mask);
BGRX = _mm_or_si128(BGRX, packed);
}
/* Get the G value */
{
const __m128i c48 = _mm_set1_epi16(48);
const __m128i d48 = _mm_unpackhi_epi16(_mm_mullo_epi16(D, c48), _mm_mulhi_epi16(D, c48));
const __m128i c120 = _mm_set1_epi16(120);
const __m128i e120 = _mm_unpackhi_epi16(_mm_mullo_epi16(E, c120), _mm_mulhi_epi16(E, c120));
const __m128i de = _mm_add_epi32(d48, e120);
const __m128i Gs = _mm_sub_epi32(C, de);
const __m128i G32 = _mm_srai_epi32(Gs, 8);
const __m128i G16 = _mm_packs_epi32(G32, _mm_setzero_si128());
const __m128i G = _mm_packus_epi16(G16, _mm_setzero_si128());
const __m128i mask = _mm_set_epi32(0x80800380, 0x80800280, 0x80800180, 0x80800080);
const __m128i packed = _mm_shuffle_epi8(G, mask);
BGRX = _mm_or_si128(BGRX, packed);
}
/* Get the B value */
{
const __m128i c475 = _mm_set1_epi16(475);
const __m128i d475 = _mm_unpackhi_epi16(_mm_mullo_epi16(D, c475), _mm_mulhi_epi16(D, c475));
const __m128i Bs = _mm_add_epi32(C, d475);
const __m128i B32 = _mm_srai_epi32(Bs, 8);
const __m128i B16 = _mm_packs_epi32(B32, _mm_setzero_si128());
const __m128i B = _mm_packus_epi16(B16, _mm_setzero_si128());
const __m128i mask = _mm_set_epi32(0x80808003, 0x80808002, 0x80808001, 0x80808000);
const __m128i packed = _mm_shuffle_epi8(B, mask);
BGRX = _mm_or_si128(BGRX, packed);
}
}
_mm_storeu_si128(dst++, BGRX);
YData += 4;
UData += 4;
VData += 4;
}
}
return PRIMITIVES_SUCCESS;
}
static pstatus_t ssse3_YUV444ToRGB_8u_P3AC4R(const BYTE** pSrc, const UINT32* srcStep,
BYTE* pDst, UINT32 dstStep, UINT32 DstFormat,
const prim_size_t* roi)
{
if (roi->width % 4 != 0)
return generic->YUV444ToRGB_8u_P3AC4R(pSrc, srcStep, pDst, dstStep, DstFormat, roi);
switch (DstFormat)
{
case PIXEL_FORMAT_BGRX32:
case PIXEL_FORMAT_BGRA32:
return ssse3_YUV444ToRGB_8u_P3AC4R_BGRX(pSrc, srcStep, pDst, dstStep, roi);
default:
return generic->YUV444ToRGB_8u_P3AC4R(pSrc, srcStep, pDst, dstStep, DstFormat, roi);
}
}
/****************************************************************************/
/* SSSE3 RGB -> YUV420 conversion **/
@ -383,18 +493,22 @@ static pstatus_t ssse3_YUV420ToRGB(
*
*/
PRIM_ALIGN_128 static const BYTE bgrx_y_factors[] = {
9, 92, 27, 0, 9, 92, 27, 0, 9, 92, 27, 0, 9, 92, 27, 0
PRIM_ALIGN_128 static const BYTE bgrx_y_factors[] =
{
9, 92, 27, 0, 9, 92, 27, 0, 9, 92, 27, 0, 9, 92, 27, 0
};
PRIM_ALIGN_128 static const BYTE bgrx_u_factors[] = {
64, -49, -15, 0, 64, -49, -15, 0, 64, -49, -15, 0, 64, -49, -15, 0
PRIM_ALIGN_128 static const BYTE bgrx_u_factors[] =
{
64, -49, -15, 0, 64, -49, -15, 0, 64, -49, -15, 0, 64, -49, -15, 0
};
PRIM_ALIGN_128 static const BYTE bgrx_v_factors[] = {
-6, -58, 64, 0, -6, -58, 64, 0, -6, -58, 64, 0, -6, -58, 64, 0
PRIM_ALIGN_128 static const BYTE bgrx_v_factors[] =
{
-6, -58, 64, 0, -6, -58, 64, 0, -6, -58, 64, 0, -6, -58, 64, 0
};
PRIM_ALIGN_128 static const BYTE const_buf_128b[] = {
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128
PRIM_ALIGN_128 static const BYTE const_buf_128b[] =
{
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128
};
/*
@ -418,13 +532,12 @@ PRIM_ALIGN_128 static const BYTE rgbx_v_factors[] = {
/* compute the luma (Y) component from a single rgb source line */
static INLINE void ssse3_RGBToYUV420_BGRX_Y(
const BYTE* src, BYTE* dst, UINT32 width)
const BYTE* src, BYTE* dst, UINT32 width)
{
UINT32 x;
__m128i y_factors, x0, x1, x2, x3;
const __m128i* argb = (const __m128i*) src;
__m128i* ydst = (__m128i*) dst;
y_factors = _mm_load_si128((__m128i*)bgrx_y_factors);
for (x = 0; x < width; x += 16)
@ -434,24 +547,19 @@ static INLINE void ssse3_RGBToYUV420_BGRX_Y(
x1 = _mm_load_si128(argb++); // 2nd 4 pixels
x2 = _mm_load_si128(argb++); // 3rd 4 pixels
x3 = _mm_load_si128(argb++); // 4th 4 pixels
/* multiplications and subtotals */
x0 = _mm_maddubs_epi16(x0, y_factors);
x1 = _mm_maddubs_epi16(x1, y_factors);
x2 = _mm_maddubs_epi16(x2, y_factors);
x3 = _mm_maddubs_epi16(x3, y_factors);
/* the total sums */
x0 = _mm_hadd_epi16(x0, x1);
x2 = _mm_hadd_epi16(x2, x3);
/* shift the results */
x0 = _mm_srli_epi16(x0, 7);
x2 = _mm_srli_epi16(x2, 7);
/* pack the 16 words into bytes */
x0 = _mm_packus_epi16(x0, x2);
/* save to y plane */
_mm_storeu_si128(ydst++, x0);
}
@ -460,18 +568,15 @@ static INLINE void ssse3_RGBToYUV420_BGRX_Y(
/* compute the chrominance (UV) components from two rgb source lines */
static INLINE void ssse3_RGBToYUV420_BGRX_UV(
const BYTE* src1, const BYTE* src2,
BYTE* dst1, BYTE* dst2, UINT32 width)
const BYTE* src1, const BYTE* src2,
BYTE* dst1, BYTE* dst2, UINT32 width)
{
UINT32 x;
__m128i vector128, u_factors, v_factors, x0, x1, x2, x3, x4, x5;
const __m128i* rgb1 = (const __m128i*)src1;
const __m128i* rgb2 = (const __m128i*)src2;
__m64* udst = (__m64*)dst1;
__m64* vdst = (__m64*)dst2;
vector128 = _mm_load_si128((__m128i*)const_buf_128b);
u_factors = _mm_load_si128((__m128i*)bgrx_u_factors);
v_factors = _mm_load_si128((__m128i*)bgrx_v_factors);
@ -482,68 +587,53 @@ static INLINE void ssse3_RGBToYUV420_BGRX_UV(
x0 = _mm_load_si128(rgb1++);
x4 = _mm_load_si128(rgb2++);
x0 = _mm_avg_epu8(x0, x4);
x1 = _mm_load_si128(rgb1++);
x4 = _mm_load_si128(rgb2++);
x1 = _mm_avg_epu8(x1, x4);
x2 = _mm_load_si128(rgb1++);
x4 = _mm_load_si128(rgb2++);
x2 = _mm_avg_epu8(x2, x4);
x3 = _mm_load_si128(rgb1++);
x4 = _mm_load_si128(rgb2++);
x3 = _mm_avg_epu8(x3, x4);
// subsample these 16x1 pixels into 8x1 pixels */
/**
* shuffle controls
* c = a[0],a[2],b[0],b[2] == 10 00 10 00 = 0x88
* c = a[1],a[3],b[1],b[3] == 11 01 11 01 = 0xdd
*/
x4 = _mm_castps_si128( _mm_shuffle_ps(_mm_castsi128_ps(x0), _mm_castsi128_ps(x1), 0x88) );
x0 = _mm_castps_si128( _mm_shuffle_ps(_mm_castsi128_ps(x0), _mm_castsi128_ps(x1), 0xdd) );
x4 = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(x0), _mm_castsi128_ps(x1), 0x88));
x0 = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(x0), _mm_castsi128_ps(x1), 0xdd));
x0 = _mm_avg_epu8(x0, x4);
x4 = _mm_castps_si128( _mm_shuffle_ps(_mm_castsi128_ps(x2), _mm_castsi128_ps(x3), 0x88) );
x1 = _mm_castps_si128( _mm_shuffle_ps(_mm_castsi128_ps(x2), _mm_castsi128_ps(x3), 0xdd) );
x4 = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(x2), _mm_castsi128_ps(x3), 0x88));
x1 = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(x2), _mm_castsi128_ps(x3), 0xdd));
x1 = _mm_avg_epu8(x1, x4);
/* multiplications and subtotals */
x2 = _mm_maddubs_epi16(x0, u_factors);
x3 = _mm_maddubs_epi16(x1, u_factors);
x4 = _mm_maddubs_epi16(x0, v_factors);
x5 = _mm_maddubs_epi16(x1, v_factors);
/* the total sums */
x0 = _mm_hadd_epi16(x2, x3);
x1 = _mm_hadd_epi16(x4, x5);
/* shift the results */
x0 = _mm_srai_epi16(x0, 7);
x1 = _mm_srai_epi16(x1, 7);
/* pack the 16 words into bytes */
x0 = _mm_packs_epi16(x0, x1);
/* add 128 */
x0 = _mm_add_epi8(x0, vector128);
/* the lower 8 bytes go to the u plane */
_mm_storel_pi(udst++, _mm_castsi128_ps(x0));
/* the upper 8 bytes go to the v plane */
_mm_storeh_pi(vdst++, _mm_castsi128_ps(x0));
}
}
static pstatus_t ssse3_RGBToYUV420_BGRX(
const BYTE* pSrc, UINT32 srcFormat, UINT32 srcStep,
BYTE* pDst[3], UINT32 dstStep[3],
const prim_size_t* roi)
const BYTE* pSrc, UINT32 srcFormat, UINT32 srcStep,
BYTE* pDst[3], UINT32 dstStep[3],
const prim_size_t* roi)
{
UINT32 y;
const BYTE* argb = pSrc;
@ -561,15 +651,13 @@ static pstatus_t ssse3_RGBToYUV420_BGRX(
return generic->RGBToYUV420_8u_P3AC4R(pSrc, srcFormat, srcStep, pDst, dstStep, roi);
}
for (y = 0; y < roi->height-1; y+=2)
for (y = 0; y < roi->height - 1; y += 2)
{
const BYTE* line1 = argb;
const BYTE* line2 = argb + srcStep;
ssse3_RGBToYUV420_BGRX_UV(line1, line2, udst, vdst, roi->width);
ssse3_RGBToYUV420_BGRX_Y(line1, ydst, roi->width);
ssse3_RGBToYUV420_BGRX_Y(line2, ydst + dstStep[0], roi->width);
argb += 2 * srcStep;
ydst += 2 * dstStep[0];
udst += 1 * dstStep[1];
@ -587,21 +675,569 @@ static pstatus_t ssse3_RGBToYUV420_BGRX(
}
static pstatus_t ssse3_RGBToYUV420(
const BYTE* pSrc, UINT32 srcFormat, UINT32 srcStep,
BYTE* pDst[3], UINT32 dstStep[3],
const prim_size_t* roi)
const BYTE* pSrc, UINT32 srcFormat, UINT32 srcStep,
BYTE* pDst[3], UINT32 dstStep[3],
const prim_size_t* roi)
{
switch (srcFormat)
{
case PIXEL_FORMAT_BGRX32:
case PIXEL_FORMAT_BGRA32:
return ssse3_RGBToYUV420_BGRX(pSrc, srcFormat, srcStep, pDst, dstStep, roi);
default:
return generic->RGBToYUV420_8u_P3AC4R(pSrc, srcFormat, srcStep, pDst, dstStep, roi);
}
}
#elif defined(WITH_NEON)
static INLINE uint8x8_t neon_YUV2R(int32x4_t Ch, int32x4_t Cl,
int16x4_t Dh, int16x4_t Dl,
int16x4_t Eh, int16x4_t El)
{
/* R = (256 * Y + 403 * (V - 128)) >> 8 */
const int16x4_t c403 = vdup_n_s16(403);
const int32x4_t CEh = vmlal_s16(Ch, Eh, c403);
const int32x4_t CEl = vmlal_s16(Cl, El, c403);
const int32x4_t Rh = vrshrq_n_s32(CEh, 8);
const int32x4_t Rl = vrshrq_n_s32(CEl, 8);
const int16x8_t R = vcombine_s16(vqmovn_s32(Rl), vqmovn_s32(Rh));
return vqmovun_s16(R);
}
static INLINE uint8x8_t neon_YUV2G(int32x4_t Ch, int32x4_t Cl,
int16x4_t Dh, int16x4_t Dl,
int16x4_t Eh, int16x4_t El)
{
/* G = (256L * Y - 48 * (U - 128) - 120 * (V - 128)) >> 8 */
const int16x4_t c48 = vdup_n_s16(48);
const int16x4_t c120 = vdup_n_s16(120);
const int32x4_t CDh = vmlsl_s16(Ch, Dh, c48);
const int32x4_t CDl = vmlsl_s16(Cl, Dl, c48);
const int32x4_t CDEh = vmlsl_s16(CDh, Eh, c120);
const int32x4_t CDEl = vmlsl_s16(CDl, El, c120);
const int32x4_t Gh = vrshrq_n_s32(CDEh, 8);
const int32x4_t Gl = vrshrq_n_s32(CDEl, 8);
const int16x8_t G = vcombine_s16(vqmovn_s32(Gl), vqmovn_s32(Gh));
return vqmovun_s16(G);
}
static INLINE uint8x8_t neon_YUV2B(int32x4_t Ch, int32x4_t Cl,
int16x4_t Dh, int16x4_t Dl,
int16x4_t Eh, int16x4_t El)
{
/* B = (256L * Y + 475 * (U - 128)) >> 8*/
const int16x4_t c475 = vdup_n_s16(475);
const int32x4_t CDh = vmlal_s16(Ch, Dh, c475);
const int32x4_t CDl = vmlal_s16(Ch, Dl, c475);
const int32x4_t Bh = vrshrq_n_s32(CDh, 8);
const int32x4_t Bl = vrshrq_n_s32(CDl, 8);
const int16x8_t B = vcombine_s16(vqmovn_s32(Bl), vqmovn_s32(Bh));
return vqmovun_s16(B);
}
static INLINE pstatus_t neon_YUV420ToX(
const BYTE* pSrc[3], const UINT32 srcStep[3],
BYTE* pDst, UINT32 dstStep,
const prim_size_t* roi, const uint8_t rPos, const uint8_t gPos,
const uint8_t bPos, const uint8_t aPos)
{
UINT32 y;
const UINT32 nWidth = roi->width;
const UINT32 nHeight = roi->height;
const int16x8_t c128 = vdupq_n_s16(128);
for (y = 0; y < nHeight; y += 2)
{
const uint8_t* pY1 = pSrc[0] + y * srcStep[0];
const uint8_t* pY2 = pY1 + srcStep[0];
const uint8_t* pU = pSrc[1] + (y / 2) * srcStep[1];
const uint8_t* pV = pSrc[2] + (y / 2) * srcStep[2];
uint8_t* pRGB1 = pDst + y * dstStep;
uint8_t* pRGB2 = pRGB1 + dstStep;
UINT32 x;
const BOOL lastY = y >= nHeight - 1;
for (x = 0; x < nWidth;)
{
const BOOL lastX = (nWidth - x) < 16;
const uint8x8_t Uraw = vld1_u8(pU);
const uint8x8x2_t Uu = vzip_u8(Uraw, Uraw);
const int16x8_t U1 = vreinterpretq_s16_u16(vmovl_u8(Uu.val[0]));
const int16x8_t U2 = vreinterpretq_s16_u16(vmovl_u8(Uu.val[1]));
const uint8x8_t Vraw = vld1_u8(pV);
const uint8x8x2_t Vu = vzip_u8(Vraw, Vraw);
const int16x8_t V1 = vreinterpretq_s16_u16(vmovl_u8(Vu.val[0]));
const int16x8_t V2 = vreinterpretq_s16_u16(vmovl_u8(Vu.val[1]));
const int16x8_t D1 = vsubq_s16(U1, c128);
const int16x4_t D1h = vget_high_s16(D1);
const int16x4_t D1l = vget_low_s16(D1);
const int16x8_t E1 = vsubq_s16(V1, c128);
const int16x4_t E1h = vget_high_s16(E1);
const int16x4_t E1l = vget_low_s16(E1);
const int16x8_t D2 = vsubq_s16(U2, c128);
const int16x4_t D2h = vget_high_s16(D2);
const int16x4_t D2l = vget_low_s16(D2);
const int16x8_t E2 = vsubq_s16(V2, c128);
const int16x4_t E2h = vget_high_s16(E2);
const int16x4_t E2l = vget_low_s16(E2);
uint8x8x4_t bgrx;
bgrx.val[aPos] = vdup_n_u8(0xFF);
{
const uint8x8_t Y1u = vld1_u8(pY1);
const int16x8_t Y1 = vreinterpretq_s16_u16(vmovl_u8(Y1u));
const int32x4_t Ch = vmulq_n_s32(vmovl_s16(vget_high_s16(Y1)), 256); /* Y * 256 */
const int32x4_t Cl = vmulq_n_s32(vmovl_s16(vget_low_s16(Y1)), 256); /* Y * 256 */
bgrx.val[rPos] = neon_YUV2R(Ch, Cl, D1h, D1l, E1h, E1l);
bgrx.val[gPos] = neon_YUV2G(Ch, Cl, D1h, D1l, E1h, E1l);
bgrx.val[bPos] = neon_YUV2B(Ch, Cl, D1h, D1l, E1h, E1l);
vst4_u8(pRGB1, bgrx);
pRGB1 += 32;
pY1 += 8;
x += 8;
}
if (!lastX)
{
const uint8x8_t Y1u = vld1_u8(pY1);
const int16x8_t Y1 = vreinterpretq_s16_u16(vmovl_u8(Y1u));
const int32x4_t Ch = vmulq_n_s32(vmovl_s16(vget_high_s16(Y1)), 256); /* Y * 256 */
const int32x4_t Cl = vmulq_n_s32(vmovl_s16(vget_low_s16(Y1)), 256); /* Y * 256 */
bgrx.val[rPos] = neon_YUV2R(Ch, Cl, D2h, D2l, E2h, E2l);
bgrx.val[gPos] = neon_YUV2G(Ch, Cl, D2h, D2l, E2h, E2l);
bgrx.val[bPos] = neon_YUV2B(Ch, Cl, D2h, D2l, E2h, E2l);
vst4_u8(pRGB1, bgrx);
pRGB1 += 32;
pY1 += 8;
x += 8;
}
if (!lastY)
{
const uint8x8_t Y2u = vld1_u8(pY2);
const int16x8_t Y2 = vreinterpretq_s16_u16(vmovl_u8(Y2u));
const int32x4_t Ch = vmulq_n_s32(vmovl_s16(vget_high_s16(Y2)), 256); /* Y * 256 */
const int32x4_t Cl = vmulq_n_s32(vmovl_s16(vget_low_s16(Y2)), 256); /* Y * 256 */
bgrx.val[rPos] = neon_YUV2R(Ch, Cl, D1h, D1l, E1h, E1l);
bgrx.val[gPos] = neon_YUV2G(Ch, Cl, D1h, D1l, E1h, E1l);
bgrx.val[bPos] = neon_YUV2B(Ch, Cl, D1h, D1l, E1h, E1l);
vst4_u8(pRGB2, bgrx);
pRGB2 += 32;
pY2 += 8;
if (!lastX)
{
const uint8x8_t Y2u = vld1_u8(pY2);
const int16x8_t Y2 = vreinterpretq_s16_u16(vmovl_u8(Y2u));
const int32x4_t Ch = vmulq_n_s32(vmovl_s16(vget_high_s16(Y2)), 256); /* Y * 256 */
const int32x4_t Cl = vmulq_n_s32(vmovl_s16(vget_low_s16(Y2)), 256); /* Y * 256 */
bgrx.val[rPos] = neon_YUV2R(Ch, Cl, D2h, D2l, E2h, E2l);
bgrx.val[gPos] = neon_YUV2G(Ch, Cl, D2h, D2l, E2h, E2l);
bgrx.val[bPos] = neon_YUV2B(Ch, Cl, D2h, D2l, E2h, E2l);
vst4_u8(pRGB2, bgrx);
pRGB2 += 32;
pY2 += 8;
}
}
pU += 8;
pV += 8;
}
}
return PRIMITIVES_SUCCESS;
}
static pstatus_t neon_YUV420ToRGB_8u_P3AC4R(
const BYTE* pSrc[3], const UINT32 srcStep[3],
BYTE* pDst, UINT32 dstStep, UINT32 DstFormat,
const prim_size_t* roi)
{
switch (DstFormat)
{
case PIXEL_FORMAT_BGRA32:
case PIXEL_FORMAT_BGRX32:
return neon_YUV420ToX(pSrc, srcStep, pDst, dstStep, roi, 2, 1, 0, 3);
case PIXEL_FORMAT_RGBA32:
case PIXEL_FORMAT_RGBX32:
return neon_YUV420ToX(pSrc, srcStep, pDst, dstStep, roi, 0, 1, 2, 3);
case PIXEL_FORMAT_ARGB32:
case PIXEL_FORMAT_XRGB32:
return neon_YUV420ToX(pSrc, srcStep, pDst, dstStep, roi, 1, 2, 3, 0);
case PIXEL_FORMAT_ABGR32:
case PIXEL_FORMAT_XBGR32:
return neon_YUV420ToX(pSrc, srcStep, pDst, dstStep, roi, 3, 2, 1, 0);
default:
return generic->YUV420ToRGB_8u_P3AC4R(pSrc, srcStep, pDst, dstStep, DstFormat, roi);
}
}
static INLINE pstatus_t neon_YUV444ToX(
const BYTE* pSrc[3], const UINT32 srcStep[3],
BYTE* pDst, UINT32 dstStep,
const prim_size_t* roi, const uint8_t rPos, const uint8_t gPos,
const uint8_t bPos, const uint8_t aPos)
{
UINT32 y;
const UINT32 nWidth = roi->width;
const UINT32 nHeight = roi->height;
const UINT32 yPad = srcStep[0] - roi->width;
const UINT32 uPad = srcStep[1] - roi->width;
const UINT32 vPad = srcStep[2] - roi->width;
const UINT32 dPad = dstStep - roi->width * 4;
const uint8_t* pY = pSrc[0];
const uint8_t* pU = pSrc[1];
const uint8_t* pV = pSrc[2];
uint8_t* pRGB = pDst;
const int16x8_t c128 = vdupq_n_s16(128);
const int16x4_t c48 = vdup_n_s16(48);
const int16x4_t c120 = vdup_n_s16(120);
const int16x4_t c403 = vdup_n_s16(403);
const int16x4_t c475 = vdup_n_s16(475);
const DWORD pad = nWidth % 8;
for (y = 0; y < nHeight; y++)
{
UINT32 x;
for (x = 0; x < nWidth - pad; x += 8)
{
const uint8x8_t Yu = vld1_u8(pY);
const int16x8_t Y = vreinterpretq_s16_u16(vmovl_u8(Yu));
const uint8x8_t Uu = vld1_u8(pU);
const int16x8_t U = vreinterpretq_s16_u16(vmovl_u8(Uu));
const uint8x8_t Vu = vld1_u8(pV);
const int16x8_t V = vreinterpretq_s16_u16(vmovl_u8(Vu));
/* Do the calculations on Y in 32bit width, the result of 255 * 256 does not fit
* a signed 16 bit value. */
const int32x4_t Ch = vmulq_n_s32(vmovl_s16(vget_high_s16(Y)), 256); /* Y * 256 */
const int32x4_t Cl = vmulq_n_s32(vmovl_s16(vget_low_s16(Y)), 256); /* Y * 256 */
const int16x8_t D = vsubq_s16(U, c128);
const int16x4_t Dh = vget_high_s16(D);
const int16x4_t Dl = vget_low_s16(D);
const int16x8_t E = vsubq_s16(V, c128);
const int16x4_t Eh = vget_high_s16(E);
const int16x4_t El = vget_low_s16(E);
uint8x8x4_t bgrx;
{
/* B = (256L * Y + 475 * (U - 128)) >> 8*/
const int32x4_t CDh = vmlal_s16(Ch, Dh, c475);
const int32x4_t CDl = vmlal_s16(Cl, Dl, c475);
const int32x4_t Bh = vrshrq_n_s32(CDh, 8);
const int32x4_t Bl = vrshrq_n_s32(CDl, 8);
const int16x8_t B = vcombine_s16(vqmovn_s32(Bl), vqmovn_s32(Bh));
bgrx.val[bPos] = vqmovun_s16(B);
}
{
/* G = (256L * Y - 48 * (U - 128) - 120 * (V - 128)) >> 8 */
const int32x4_t CDh = vmlsl_s16(Ch, Dh, c48);
const int32x4_t CDl = vmlsl_s16(Cl, Dl, c48);
const int32x4_t CDEh = vmlsl_s16(CDh, Eh, c120);
const int32x4_t CDEl = vmlsl_s16(CDl, El, c120);
const int32x4_t Gh = vrshrq_n_s32(CDEh, 8);
const int32x4_t Gl = vrshrq_n_s32(CDEl, 8);
const int16x8_t G = vcombine_s16(vqmovn_s32(Gl), vqmovn_s32(Gh));
bgrx.val[gPos] = vqmovun_s16(G);
}
{
/* R = (256 * Y + 403 * (V - 128)) >> 8 */
const int32x4_t CEh = vmlal_s16(Ch, Eh, c403);
const int32x4_t CEl = vmlal_s16(Cl, El, c403);
const int32x4_t Rh = vrshrq_n_s32(CEh, 8);
const int32x4_t Rl = vrshrq_n_s32(CEl, 8);
const int16x8_t R = vcombine_s16(vqmovn_s32(Rl), vqmovn_s32(Rh));
bgrx.val[rPos] = vqmovun_s16(R);
}
{
/* A */
bgrx.val[aPos] = vdup_n_u8(0xFF);
}
vst4_u8(pRGB, bgrx);
pRGB += 32;
pY += 8;
pU += 8;
pV += 8;
}
for (x = 0; x < pad; x++)
{
const BYTE Y = *pY++;
const BYTE U = *pU++;
const BYTE V = *pV++;
const BYTE r = YUV2R(Y, U, V);
const BYTE g = YUV2G(Y, U, V);
const BYTE b = YUV2B(Y, U, V);
pRGB[aPos] = 0xFF;
pRGB[rPos] = r;
pRGB[gPos] = g;
pRGB[bPos] = b;
pRGB += 4;
}
pRGB += dPad;
pY += yPad;
pU += uPad;
pV += vPad;
}
return PRIMITIVES_SUCCESS;
}
static pstatus_t neon_YUV444ToRGB_8u_P3AC4R(
const BYTE* pSrc[3], const UINT32 srcStep[3],
BYTE* pDst, UINT32 dstStep, UINT32 DstFormat,
const prim_size_t* roi)
{
switch (DstFormat)
{
case PIXEL_FORMAT_BGRA32:
case PIXEL_FORMAT_BGRX32:
return neon_YUV444ToX(pSrc, srcStep, pDst, dstStep, roi, 2, 1, 0, 3);
case PIXEL_FORMAT_RGBA32:
case PIXEL_FORMAT_RGBX32:
return neon_YUV444ToX(pSrc, srcStep, pDst, dstStep, roi, 0, 1, 2, 3);
case PIXEL_FORMAT_ARGB32:
case PIXEL_FORMAT_XRGB32:
return neon_YUV444ToX(pSrc, srcStep, pDst, dstStep, roi, 1, 2, 3, 0);
case PIXEL_FORMAT_ABGR32:
case PIXEL_FORMAT_XBGR32:
return neon_YUV444ToX(pSrc, srcStep, pDst, dstStep, roi, 3, 2, 1, 0);
default:
return generic->YUV444ToRGB_8u_P3AC4R(pSrc, srcStep, pDst, dstStep, DstFormat, roi);
}
}
static pstatus_t neon_YUV420CombineToYUV444(
const BYTE* pMainSrc[3], const UINT32 srcMainStep[3],
const BYTE* pAuxSrc[3], const UINT32 srcAuxStep[3],
BYTE* pDst[3], const UINT32 dstStep[3],
const prim_size_t* roi)
{
UINT32 x, y;
const UINT32 nWidth = roi->width;
const UINT32 nHeight = roi->height;
const UINT32 halfWidth = nWidth / 2, halfHeight = nHeight / 2;
const UINT32 oddY = 1;
const UINT32 evenY = 0;
/* The auxilary frame is aligned to multiples of 16x16.
* We need the padded height for B4 and B5 conversion. */
const UINT32 padHeigth = roi->height + 16 - roi->height % 16;
if (pMainSrc && pMainSrc[0] && pMainSrc[1] && pMainSrc[2])
{
/* Y data is already here... */
/* B1 */
for (y = 0; y < nHeight; y++)
{
const BYTE* Ym = pMainSrc[0] + srcMainStep[0] * y;
BYTE* pY = pDst[0] + dstStep[0] * y;
memcpy(pY, Ym, nWidth);
}
/* The first half of U, V are already here part of this frame. */
/* B2 and B3 */
for (y = 0; y < halfHeight; y++)
{
const UINT32 val2y = (2 * y + evenY);
const BYTE* Um = pMainSrc[1] + srcMainStep[1] * y;
const BYTE* Vm = pMainSrc[2] + srcMainStep[2] * y;
BYTE* pU = pDst[1] + dstStep[1] * val2y;
BYTE* pV = pDst[2] + dstStep[2] * val2y;
BYTE* pU1 = pU + dstStep[1];
BYTE* pV1 = pV + dstStep[2];
for (x = 0; x + 16 < halfWidth; x += 16)
{
{
const uint8x16_t u = vld1q_u8(Um);
uint8x16x2_t u2x;
u2x.val[0] = u;
u2x.val[1] = u;
vst2q_u8(pU, u2x);
vst2q_u8(pU1, u2x);
Um += 16;
pU += 32;
pU1 += 32;
}
{
const uint8x16_t v = vld1q_u8(Vm);
uint8x16x2_t v2x;
v2x.val[0] = v;
v2x.val[1] = v;
vst2q_u8(pV, v2x);
vst2q_u8(pV1, v2x);
Vm += 16;
pV += 32;
pV1 += 32;
}
}
for (; x < halfWidth; x++)
{
const BYTE u = *Um++;
const BYTE v = *Vm++;
*pU++ = u;
*pU++ = u;
*pU1++ = u;
*pU1++ = u;
*pV++ = v;
*pV++ = v;
*pV1++ = v;
*pV1++ = v;
}
}
}
if (!pAuxSrc || !pAuxSrc[0] || !pAuxSrc[1] || !pAuxSrc[2])
return PRIMITIVES_SUCCESS;
/* The second half of U and V is a bit more tricky... */
/* B4 and B5 */
for (y = 0; y < padHeigth; y += 16)
{
const BYTE* Ya = pAuxSrc[0] + srcAuxStep[0] * y;
UINT32 x;
BYTE* pU = pDst[1] + dstStep[1] * (y + 1);
BYTE* pV = pDst[2] + dstStep[2] * (y + 1);
for (x = 0; x < 8; x++)
{
if (y + x >= nHeight)
continue;
memcpy(pU, Ya, nWidth);
pU += dstStep[1] * 2;
Ya += srcAuxStep[0];
}
for (x = 0; x < 8; x++)
{
if (y + x >= nHeight)
continue;
memcpy(pV, Ya, nWidth);
pV += dstStep[1] * 2;
Ya += srcAuxStep[0];
}
}
/* B6 and B7 */
for (y = 0; y < halfHeight; y++)
{
const UINT32 val2y = (y * 2 + evenY);
const BYTE* Ua = pAuxSrc[1] + srcAuxStep[1] * y;
const BYTE* Va = pAuxSrc[2] + srcAuxStep[2] * y;
BYTE* pU = pDst[1] + dstStep[1] * val2y;
BYTE* pV = pDst[2] + dstStep[2] * val2y;
for (x = 0; x + 16 < halfWidth; x += 16)
{
{
const uint8x16_t u = vld1q_u8(Ua);
uint8x16x2_t uu = vld2q_u8(pU);
uu.val[1] = u;
vst2q_u8(pU, uu);
Ua += 16;
pU += 32;
}
{
const uint8x16_t v = vld1q_u8(Va);
uint8x16x2_t vv = vld2q_u8(pV);
vv.val[1] = v;
vst2q_u8(pV, vv);
Va += 16;
pV += 32;
}
}
for (; x < halfWidth; x++)
{
pU++;
*pU++ = *Ua++;
pV++;
*pV++ = *Va++;
}
}
/* Filter */
for (y = 0; y < halfHeight; y++)
{
const UINT32 val2y = (y * 2 + evenY);
const UINT32 val2y1 = val2y + oddY;
BYTE* pU = pDst[1] + dstStep[1] * val2y;
BYTE* pV = pDst[2] + dstStep[2] * val2y;
BYTE* pU1 = pU + dstStep[1];
BYTE* pV1 = pV + dstStep[2];
if (val2y1 > nHeight)
continue;
for (x = 0; x + 16 < halfWidth; x += 16)
{
{
/* U = (U2x,2y << 2) - U2x1,2y - U2x,2y1 - U2x1,2y1 */
uint8x8x2_t u = vld2_u8(pU);
const int16x8_t up = vreinterpretq_s16_u16(vshll_n_u8(u.val[0], 2)); /* Ux2,2y << 2 */
const uint8x8x2_t u1 = vld2_u8(pU1);
const uint16x8_t usub = vaddl_u8(u1.val[1], u1.val[0]); /* U2x,2y1 + U2x1,2y1 */
const int16x8_t us = vreinterpretq_s16_u16(vaddw_u8(usub,
u.val[1])); /* U2x1,2y + U2x,2y1 + U2x1,2y1 */
const int16x8_t un = vsubq_s16(up, us);
const uint8x8_t u8 = vqmovun_s16(un); /* CLIP(un) */
u.val[0] = u8;
vst2_u8(pU, u);
pU += 16;
pU1 += 16;
}
{
/* V = (V2x,2y << 2) - V2x1,2y - V2x,2y1 - V2x1,2y1 */
uint8x8x2_t v = vld2_u8(pV);
const int16x8_t vp = vreinterpretq_s16_u16(vshll_n_u8(v.val[0], 2)); /* Vx2,2y << 2 */
const uint8x8x2_t v1 = vld2_u8(pV1);
const uint16x8_t vsub = vaddl_u8(v1.val[1], v1.val[0]); /* V2x,2y1 + V2x1,2y1 */
const int16x8_t vs = vreinterpretq_s16_u16(vaddw_u8(vsub,
v.val[1])); /* V2x1,2y + V2x,2y1 + V2x1,2y1 */
const int16x8_t vn = vsubq_s16(vp, vs);
const uint8x8_t v8 = vqmovun_s16(vn); /* CLIP(vn) */
v.val[0] = v8;
vst2_u8(pV, v);
pV += 16;
pV1 += 16;
}
}
for (; x < halfWidth; x++)
{
const UINT32 val2x = (x * 2);
const UINT32 val2x1 = val2x + 1;
const INT32 up = pU[val2x] * 4;
const INT32 vp = pV[val2x] * 4;
INT32 u2020;
INT32 v2020;
if (val2x1 > nWidth)
continue;
u2020 = up - pU[val2x1] - pU1[val2x] - pU1[val2x1];
v2020 = vp - pV[val2x1] - pV1[val2x] - pV1[val2x1];
*pU = CLIP(u2020);
*pV = CLIP(v2020);
pU += 2;
pV += 2;
}
}
return PRIMITIVES_SUCCESS;
}
#endif
void primitives_init_YUV_opt(primitives_t* prims)
@ -615,6 +1251,16 @@ void primitives_init_YUV_opt(primitives_t* prims)
{
prims->RGBToYUV420_8u_P3AC4R = ssse3_RGBToYUV420;
prims->YUV420ToRGB_8u_P3AC4R = ssse3_YUV420ToRGB;
prims->YUV444ToRGB_8u_P3AC4R = ssse3_YUV444ToRGB_8u_P3AC4R;
}
#elif defined(WITH_NEON)
if (IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE))
{
prims->YUV420ToRGB_8u_P3AC4R = neon_YUV420ToRGB_8u_P3AC4R;
prims->YUV444ToRGB_8u_P3AC4R = neon_YUV444ToRGB_8u_P3AC4R;
prims->YUV420CombineToYUV444 = neon_YUV420CombineToYUV444;
}
#endif

View File

@ -302,9 +302,9 @@ static INLINE void writeScanlineRGB(BYTE* dst, DWORD formatSize, UINT32 DstForma
for (x = 0; x < width; x++)
{
const BYTE R = *r++;
const BYTE G = *g++;
const BYTE B = *b++;
const BYTE R = CLIP(*r++);
const BYTE G = CLIP(*g++);
const BYTE B = CLIP(*b++);
*dst++ = R;
*dst++ = G;
*dst++ = B;
@ -318,9 +318,9 @@ static INLINE void writeScanlineBGR(BYTE* dst, DWORD formatSize, UINT32 DstForma
for (x = 0; x < width; x++)
{
const BYTE R = *r++;
const BYTE G = *g++;
const BYTE B = *b++;
const BYTE R = CLIP(*r++);
const BYTE G = CLIP(*g++);
const BYTE B = CLIP(*b++);
*dst++ = B;
*dst++ = G;
*dst++ = R;
@ -334,9 +334,9 @@ static INLINE void writeScanlineBGRX(BYTE* dst, DWORD formatSize, UINT32 DstForm
for (x = 0; x < width; x++)
{
const BYTE R = *r++;
const BYTE G = *g++;
const BYTE B = *b++;
const BYTE R = CLIP(*r++);
const BYTE G = CLIP(*g++);
const BYTE B = CLIP(*b++);
*dst++ = B;
*dst++ = G;
*dst++ = R;
@ -351,9 +351,9 @@ static INLINE void writeScanlineRGBX(BYTE* dst, DWORD formatSize, UINT32 DstForm
for (x = 0; x < width; x++)
{
const BYTE R = *r++;
const BYTE G = *g++;
const BYTE B = *b++;
const BYTE R = CLIP(*r++);
const BYTE G = CLIP(*g++);
const BYTE B = CLIP(*b++);
*dst++ = R;
*dst++ = G;
*dst++ = B;
@ -368,9 +368,9 @@ static INLINE void writeScanlineXBGR(BYTE* dst, DWORD formatSize, UINT32 DstForm
for (x = 0; x < width; x++)
{
const BYTE R = *r++;
const BYTE G = *g++;
const BYTE B = *b++;
const BYTE R = CLIP(*r++);
const BYTE G = CLIP(*g++);
const BYTE B = CLIP(*b++);
*dst++ = 0xFF;
*dst++ = B;
*dst++ = G;
@ -385,9 +385,9 @@ static INLINE void writeScanlineXRGB(BYTE* dst, DWORD formatSize, UINT32 DstForm
for (x = 0; x < width; x++)
{
const BYTE R = *r++;
const BYTE G = *g++;
const BYTE B = *b++;
const BYTE R = CLIP(*r++);
const BYTE G = CLIP(*g++);
const BYTE B = CLIP(*b++);
*dst++ = 0xFF;
*dst++ = R;
*dst++ = G;

File diff suppressed because it is too large Load Diff

View File

@ -129,6 +129,47 @@ static INLINE BYTE CLIP(INT32 X)
return X;
}
/**
* | R | ( | 256 0 403 | | Y | )
* | G | = ( | 256 -48 -120 | | U - 128 | ) >> 8
* | B | ( | 256 475 0 | | V - 128 | )
*/
static INLINE INT32 C(INT32 Y)
{
return (Y) - 0L;
}
static INLINE INT32 D(INT32 U)
{
return (U) - 128L;
}
static INLINE INT32 E(INT32 V)
{
return (V) - 128L;
}
static INLINE BYTE YUV2R(INT32 Y, INT32 U, INT32 V)
{
const INT32 r = (256L * C(Y) + 0L * D(U) + 403L * E(V));
const INT32 r8 = r >> 8L;
return CLIP(r8);
}
static INLINE BYTE YUV2G(INT32 Y, INT32 U, INT32 V)
{
const INT32 g = (256L * C(Y) - 48L * D(U) - 120L * E(V));
const INT32 g8 = g >> 8L;
return CLIP(g8);
}
static INLINE BYTE YUV2B(INT32 Y, INT32 U, INT32 V)
{
const INT32 b = (256L * C(Y) + 475L * D(U) + 0L * E(V));
const INT32 b8 = b >> 8L;
return CLIP(b8);
}
/* Function prototypes for all the init/deinit routines. */
FREERDP_LOCAL void primitives_init_copy(primitives_t* prims);
FREERDP_LOCAL void primitives_init_set(primitives_t* prims);

View File

@ -17,58 +17,102 @@
#endif
#include <winpr/sysinfo.h>
#include <freerdp/utils/profiler.h>
#include "prim_test.h"
static const int RGB_TRIAL_ITERATIONS = 1000;
static const int YCBCR_TRIAL_ITERATIONS = 1000;
static const float TEST_TIME = 4.0;
/* ------------------------------------------------------------------------- */
static BOOL test_RGBToRGB_16s8u_P3AC4R_func(void)
static BOOL test_RGBToRGB_16s8u_P3AC4R_func(prim_size_t roi, DWORD DstFormat)
{
INT16 ALIGN(r[4096]), ALIGN(g[4096]), ALIGN(b[4096]);
UINT32 ALIGN(out1[4096]);
UINT32 ALIGN(out2[4096]);
INT16* r;
INT16* g;
INT16* b;
BYTE* out1;
BYTE* out2;
int i;
BOOL failed = FALSE;
INT16* ptrs[3];
prim_size_t roi = { 64, 64 };
const INT16* ptrs[3];
const UINT32 rgbStride = roi.width * 2;
const UINT32 dstStride = roi.width * 4;
PROFILER_DEFINE(genericProf);
PROFILER_DEFINE(optProf);
PROFILER_CREATE(genericProf, "RGBToRGB_16s8u_P3AC4R-GENERIC");
PROFILER_CREATE(optProf, "RGBToRGB_16s8u_P3AC4R-OPTIMIZED");
r = _aligned_malloc(rgbStride * roi.height, 16);
g = _aligned_malloc(rgbStride * roi.height, 16);
b = _aligned_malloc(rgbStride * roi.height, 16);
out1 = _aligned_malloc(dstStride * roi.height, 16);
out2 = _aligned_malloc(dstStride * roi.height, 16);
winpr_RAND((BYTE*)r, sizeof(r));
winpr_RAND((BYTE*)g, sizeof(g));
winpr_RAND((BYTE*)b, sizeof(b));
if (!r || !g || !b || !out1 || !out2)
goto fail;
/* clear upper bytes */
for (i = 0; i < 4096; ++i)
#if 0
{
r[i] &= 0x00FFU;
g[i] &= 0x00FFU;
b[i] &= 0x00FFU;
}
UINT32 x, y;
for (y = 0; y < roi.height; y++)
{
for (x = 0; x < roi.width; x++)
{
r[y * roi.width + x] = 0x01;
g[y * roi.width + x] = 0x02;
b[y * roi.width + x] = 0x04;
}
}
}
#else
winpr_RAND((BYTE*)r, rgbStride * roi.height);
winpr_RAND((BYTE*)g, rgbStride * roi.height);
winpr_RAND((BYTE*)b, rgbStride * roi.height);
#endif
ptrs[0] = r;
ptrs[1] = g;
ptrs[2] = b;
if (generic->RGBToRGB_16s8u_P3AC4R((const INT16**) ptrs, 64 * 2,
(BYTE*) out1, 64 * 4, PIXEL_FORMAT_RGBA32,
&roi) != PRIMITIVES_SUCCESS)
return FALSE;
PROFILER_ENTER(genericProf);
if (optimized->RGBToRGB_16s8u_P3AC4R((const INT16**) ptrs, 64 * 2,
(BYTE*) out2, 64 * 4, PIXEL_FORMAT_RGBA32,
&roi) != PRIMITIVES_SUCCESS)
return FALSE;
if (generic->RGBToRGB_16s8u_P3AC4R(ptrs, rgbStride,
out1, dstStride, DstFormat,
&roi) != PRIMITIVES_SUCCESS)
goto fail;
for (i = 0; i < 4096; ++i)
PROFILER_EXIT(genericProf);
PROFILER_ENTER(optProf);
if (optimized->RGBToRGB_16s8u_P3AC4R(ptrs, rgbStride,
out2, dstStride, DstFormat,
&roi) != PRIMITIVES_SUCCESS)
goto fail;
PROFILER_EXIT(optProf);
if (memcmp(out1, out2, dstStride * roi.height) != 0)
{
if (out1[i] != out2[i])
for (i = 0; i < roi.width * roi.height; ++i)
{
printf("RGBToRGB-SSE FAIL: out1[%d]=0x%08"PRIx32" out2[%d]=0x%08"PRIx32"\n",
i, out1[i], i, out2[i]);
failed = TRUE;
const UINT32 o1 = ReadColor(out1 + 4 * i, DstFormat);
const UINT32 o2 = ReadColor(out2 + 4 * i, DstFormat);
if (o1 != o2)
{
printf("RGBToRGB_16s8u_P3AC4R FAIL: out1[%d]=0x%08"PRIx32" out2[%d]=0x%08"PRIx32"\n",
i, out1[i], i, out2[i]);
failed = TRUE;
}
}
}
printf("Results for %lux%lu [%s]", roi.width, roi.height, GetColorFormatName(DstFormat));
PROFILER_PRINT(genericProf);
PROFILER_PRINT(optProf);
fail:
PROFILER_FREE(genericProf);
PROFILER_FREE(optProf);
_aligned_free(r);
_aligned_free(g);
_aligned_free(b);
_aligned_free(out1);
_aligned_free(out2);
return !failed;
}
@ -76,11 +120,10 @@ static BOOL test_RGBToRGB_16s8u_P3AC4R_func(void)
static BOOL test_RGBToRGB_16s8u_P3AC4R_speed(void)
{
const prim_size_t roi64x64 = { 64, 64 };
INT16 ALIGN(r[4096+1]), ALIGN(g[4096+1]), ALIGN(b[4096+1]);
UINT32 ALIGN(dst[4096+1]);
INT16 ALIGN(r[4096 + 1]), ALIGN(g[4096 + 1]), ALIGN(b[4096 + 1]);
UINT32 ALIGN(dst[4096 + 1]);
int i;
INT16* ptrs[3];
winpr_RAND((BYTE*)r, sizeof(r));
winpr_RAND((BYTE*)g, sizeof(g));
winpr_RAND((BYTE*)b, sizeof(b));
@ -93,20 +136,20 @@ static BOOL test_RGBToRGB_16s8u_P3AC4R_speed(void)
b[i] &= 0x00FFU;
}
ptrs[0] = r+1;
ptrs[1] = g+1;
ptrs[2] = b+1;
ptrs[0] = r + 1;
ptrs[1] = g + 1;
ptrs[2] = b + 1;
if (!speed_test("RGBToRGB_16s8u_P3AC4R", "aligned", g_Iterations,
(speed_test_fkt)generic->RGBToRGB_16s8u_P3AC4R,
(speed_test_fkt)optimized->RGBToRGB_16s8u_P3AC4R,
(const INT16**) ptrs, 64 * 2, (BYTE*) dst, 64 * 4, &roi64x64))
(speed_test_fkt)generic->RGBToRGB_16s8u_P3AC4R,
(speed_test_fkt)optimized->RGBToRGB_16s8u_P3AC4R,
(const INT16**) ptrs, 64 * 2, (BYTE*) dst, 64 * 4, &roi64x64))
return FALSE;
if (!speed_test("RGBToRGB_16s8u_P3AC4R", "unaligned", g_Iterations,
(speed_test_fkt)generic->RGBToRGB_16s8u_P3AC4R,
(speed_test_fkt)optimized->RGBToRGB_16s8u_P3AC4R,
(const INT16**) ptrs, 64 * 2, ((BYTE*) dst)+1, 64 * 4, &roi64x64))
(speed_test_fkt)generic->RGBToRGB_16s8u_P3AC4R,
(speed_test_fkt)optimized->RGBToRGB_16s8u_P3AC4R,
(const INT16**) ptrs, 64 * 2, ((BYTE*) dst) + 1, 64 * 4, &roi64x64))
return FALSE;
return TRUE;
@ -124,7 +167,6 @@ static BOOL test_yCbCrToRGB_16s16s_P3P3_func(void)
INT16* out1[3];
INT16* out2[3];
prim_size_t roi = { 64, 64 };
winpr_RAND((BYTE*)y, sizeof(y));
winpr_RAND((BYTE*)cb, sizeof(cb));
winpr_RAND((BYTE*)cr, sizeof(cr));
@ -152,12 +194,13 @@ static BOOL test_yCbCrToRGB_16s16s_P3P3_func(void)
out2[0] = r2;
out2[1] = g2;
out2[2] = b2;
status = generic->yCbCrToRGB_16s16s_P3P3(in, 64 * 2, out1, 64 * 2, &roi);
if (status != PRIMITIVES_SUCCESS)
return FALSE;
status = optimized->yCbCrToRGB_16s16s_P3P3(in, 64 * 2, out2, 64 * 2, &roi);
if (status != PRIMITIVES_SUCCESS)
return FALSE;
@ -167,7 +210,8 @@ static BOOL test_yCbCrToRGB_16s16s_P3P3_func(void)
|| (ABS(g1[i] - g2[i]) > 1)
|| (ABS(b1[i] - b2[i]) > 1))
{
printf("YCbCrToRGB-SSE FAIL[%d]: %"PRId16",%"PRId16",%"PRId16" vs %"PRId16",%"PRId16",%"PRId16"\n", i,
printf("YCbCrToRGB-SSE FAIL[%d]: %"PRId16",%"PRId16",%"PRId16" vs %"PRId16",%"PRId16",%"PRId16"\n",
i,
r1[i], g1[i], b1[i], r2[i], g2[i], b2[i]);
return FALSE;
}
@ -185,7 +229,6 @@ static int test_yCbCrToRGB_16s16s_P3P3_speed(void)
int i;
const INT16* input[3];
INT16* output[3];
winpr_RAND((BYTE*)y, sizeof(y));
winpr_RAND((BYTE*)cb, sizeof(cb));
winpr_RAND((BYTE*)cr, sizeof(cr));
@ -206,9 +249,9 @@ static int test_yCbCrToRGB_16s16s_P3P3_speed(void)
output[2] = b;
if (!speed_test("yCbCrToRGB_16s16s_P3P3", "aligned", g_Iterations,
(speed_test_fkt)generic->yCbCrToRGB_16s16s_P3P3,
(speed_test_fkt)optimized->yCbCrToRGB_16s16s_P3P3,
input, 64 * 2, output, 64 * 2, &roi))
(speed_test_fkt)generic->yCbCrToRGB_16s16s_P3P3,
(speed_test_fkt)optimized->yCbCrToRGB_16s16s_P3P3,
input, 64 * 2, output, 64 * 2, &roi))
return FALSE;
return TRUE;
@ -216,24 +259,44 @@ static int test_yCbCrToRGB_16s16s_P3P3_speed(void)
int TestPrimitivesColors(int argc, char* argv[])
{
const DWORD formats[] =
{
PIXEL_FORMAT_ARGB32,
PIXEL_FORMAT_XRGB32,
PIXEL_FORMAT_ABGR32,
PIXEL_FORMAT_XBGR32,
PIXEL_FORMAT_RGBA32,
PIXEL_FORMAT_RGBX32,
PIXEL_FORMAT_BGRA32,
PIXEL_FORMAT_BGRX32
};
DWORD x;
prim_size_t roi = { 1920, 1080};
prim_test_setup(FALSE);
if (!test_RGBToRGB_16s8u_P3AC4R_func())
return 1;
if (g_TestPrimitivesPerformance)
for (x = 0; x < sizeof(formats) / sizeof(formats[0]); x++)
{
if (!test_RGBToRGB_16s8u_P3AC4R_speed())
if (!test_RGBToRGB_16s8u_P3AC4R_func(roi, formats[x]))
return 1;
}
if (!test_yCbCrToRGB_16s16s_P3P3_func())
return 1;
#if 0
if (g_TestPrimitivesPerformance)
{
if (!test_yCbCrToRGB_16s16s_P3P3_speed())
if (g_TestPrimitivesPerformance)
{
if (!test_RGBToRGB_16s8u_P3AC4R_speed())
return 1;
}
if (!test_yCbCrToRGB_16s16s_P3P3_func())
return 1;
if (g_TestPrimitivesPerformance)
{
if (!test_yCbCrToRGB_16s16s_P3P3_speed())
return 1;
}
#endif
}
return 0;

View File

@ -25,16 +25,19 @@
static BOOL test_sign16s_func(void)
{
pstatus_t status;
INT16 ALIGN(src[TEST_BUFFER_SIZE]);
INT16 ALIGN(d1[TEST_BUFFER_SIZE]);
INT16 ALIGN(d2[TEST_BUFFER_SIZE]);
INT16 ALIGN(src[TEST_BUFFER_SIZE + 16]);
INT16 ALIGN(d1[TEST_BUFFER_SIZE + 16]);
INT16 ALIGN(d2[TEST_BUFFER_SIZE + 16]);
winpr_RAND((BYTE*)src, sizeof(src));
memset(d1, 0, sizeof(d1));
memset(d2, 0, sizeof(d2));
status = generic->sign_16s(src + 1, d1 + 1, TEST_BUFFER_SIZE);
if (status != PRIMITIVES_SUCCESS)
return FALSE;
status = optimized->sign_16s(src + 1, d2 + 1, TEST_BUFFER_SIZE);
if (status != PRIMITIVES_SUCCESS)
return FALSE;
@ -42,9 +45,12 @@ static BOOL test_sign16s_func(void)
return FALSE;
status = generic->sign_16s(src + 1, d1 + 2, TEST_BUFFER_SIZE);
if (status != PRIMITIVES_SUCCESS)
return FALSE;
status = optimized->sign_16s(src + 1, d2 + 2, TEST_BUFFER_SIZE);
if (status != PRIMITIVES_SUCCESS)
return FALSE;
@ -60,15 +66,15 @@ static int test_sign16s_speed(void)
winpr_RAND((BYTE*)src, sizeof(src));
if (!speed_test("sign16s", "aligned", g_Iterations,
(speed_test_fkt)generic->sign_16s,
(speed_test_fkt)optimized->sign_16s, src + 1, dst + 1,
MAX_TEST_SIZE))
(speed_test_fkt)generic->sign_16s,
(speed_test_fkt)optimized->sign_16s, src + 1, dst + 1,
MAX_TEST_SIZE))
return FALSE;
if (!speed_test("sign16s", "unaligned", g_Iterations,
(speed_test_fkt)generic->sign_16s,
(speed_test_fkt)optimized->sign_16s, src + 1, dst + 2,
MAX_TEST_SIZE))
(speed_test_fkt)generic->sign_16s,
(speed_test_fkt)optimized->sign_16s, src + 1, dst + 2,
MAX_TEST_SIZE))
return FALSE;
return TRUE;

View File

@ -4,6 +4,7 @@
#include <winpr/print.h>
#include <freerdp/codec/color.h>
#include <winpr/wlog.h>
#include <freerdp/utils/profiler.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
@ -11,7 +12,7 @@
#define TAG __FILE__
static INT16 TEST_Y_COMPONENT[4096] =
static const INT16 TEST_Y_COMPONENT[4096] =
{
-32, +16, +64, +272, -32, -16, +0, -16,
-32, -24, -16, -8, +0, -24, -48, -72,
@ -527,7 +528,7 @@ static INT16 TEST_Y_COMPONENT[4096] =
+8, -24, -56, -88, -120, -120, -120, -120
};
static INT16 TEST_CB_COMPONENT[4096] =
static const INT16 TEST_CB_COMPONENT[4096] =
{
+1728, +1730, +1732, +1734, +1736, +1738, +1740, +1742,
+1744, +1740, +1736, +1732, +1728, +1796, +1864, +1804,
@ -1043,7 +1044,7 @@ static INT16 TEST_CB_COMPONENT[4096] =
+2160, +2168, +2176, +2184, +2192, +2192, +2192, +2192
};
static INT16 TEST_CR_COMPONENT[4096] =
static const INT16 TEST_CR_COMPONENT[4096] =
{
-2112, -2114, -2116, -2118, -2120, -2122, -2124, -2126,
-2128, -2118, -2108, -2098, -2088, -2150, -2212, -2146,
@ -1563,7 +1564,7 @@ static INT16 TEST_CR_COMPONENT[4096] =
* 64x64 XRGB Image
*/
static UINT32 TEST_XRGB_IMAGE[4096] =
static const UINT32 TEST_XRGB_IMAGE[4096] =
{
0xFF229cdf, 0xFF249de0, 0xFF259fe2, 0xFF2ca5e8, 0xFF229cdf, 0xFF229ce0, 0xFF239de0, 0xFF229ce0,
0xFF229cdf, 0xFF229cdf, 0xFF239ce0, 0xFF249ce0, 0xFF249ce0, 0xFF219ce3, 0xFF1e9ce6, 0xFF209ae2,
@ -2154,211 +2155,136 @@ static int test_bmp_cmp_dump(const BYTE* actual, const BYTE* expected, int size,
return count;
}
static void test_fill_bitmap_channel(BYTE* data, int width, int height,
BYTE value, int nChannel)
static int test_PrimitivesYCbCr(const primitives_t* prims, UINT32 format, prim_size_t roi)
{
int x, y;
BYTE* pChannel;
pChannel = data + nChannel;
for (y = 0; y < height; y++)
{
for (x = 0; x < width; x++)
{
*pChannel = value;
pChannel += 4;
}
}
}
#define TEST_FP_TYPE float
static TEST_FP_TYPE TEST_YCbCrToRGB_01[4] = { 1.403f, 0.344f, 0.714f, 1.770f };
static TEST_FP_TYPE TEST_YCbCrToRGB_02[4] = { 1.402525f, 0.343730f, 0.714401f, 1.769905f };
static TEST_FP_TYPE TEST_YCbCrToRGB_03[4] = { 1.402524948120117L, 0.3437300026416779L, 0.7144010066986084L, 1.769904971122742L };
static INT16 TEST_YCbCr_01[3] = { +3443, -1863, +272 };
static BYTE TEST_RGB_01[3] = { 247, 249, 132 };
static INT16 TEST_YCbCr_02[3] = { +1086, +1584, -2268 };
static BYTE TEST_RGB_02[3] = { 62, 195, 249 };
static INT16 TEST_YCbCr_03[3] = { -576, +2002, -2179 };
static BYTE TEST_RGB_03[3] = { 15, 137, 221 };
int test_YCbCr_fp(TEST_FP_TYPE coeffs[4], INT16 YCbCr[3], BYTE RGB[3])
{
INT16 R, G, B;
TEST_FP_TYPE Y, Cb, Cr;
TEST_FP_TYPE fR, fG, fB;
TEST_FP_TYPE fR1, fR2;
Y = (TEST_FP_TYPE)(YCbCr[0] + 4096);
Cb = (TEST_FP_TYPE)(YCbCr[1]);
Cr = (TEST_FP_TYPE)(YCbCr[2]);
#if 1
fR1 = Cr * coeffs[0];
fR2 = fR1 + Y + 16.0f;
fR = ((Cr * coeffs[0]) + Y + 16.0f);
fG = (Y - (Cb * coeffs[1]) - (Cr * coeffs[2]) + 16.0f);
fB = ((Cb * coeffs[3]) + Y + 16.0f);
printf("fR: %f fG: %f fB: %f fY: %f\n", fR, fG, fB, Y);
R = (INT16) fR;
G = (INT16) fG;
B = (INT16) fB;
printf("mR: %d mG: %d mB: %d\n", (R - 16) % 32, (G - 16) % 32, (B - 16) % 32);
printf("iR: %"PRId16" iG: %"PRId16" iB: %"PRId16"\n", R, G, B);
R >>= 5;
G >>= 5;
B >>= 5;
printf("R5: %"PRId16" G5: %"PRId16" B5: %"PRId16"\n", R, G, B);
#else
R = ((INT16)(((Cr * coeffs[0]) + Y + 16.0f)) >> 5);
G = ((INT16)((Y - (Cb * coeffs[1]) - (Cr * coeffs[2]) + 16.0f)) >> 5);
B = ((INT16)(((Cb * coeffs[3]) + Y + 16.0f)) >> 5);
#endif
if (R < 0)
R = 0;
else if (R > 255)
R = 255;
if (G < 0)
G = 0;
else if (G > 255)
G = 255;
if (B < 0)
B = 0;
else if (B > 255)
B = 255;
printf("--------------------------------\n");
printf("R: A: %3"PRId16" E: %3"PRIu8" %s\n", R, RGB[0], (R == RGB[0]) ? "" : "***");
printf("G: A: %3"PRId16" E: %3"PRIu8" %s\n", G, RGB[1], (G == RGB[1]) ? "" : "***");
printf("B: A: %3"PRId16" E: %3"PRIu8" %s\n", B, RGB[2], (B == RGB[2]) ? "" : "***");
printf("Y: %+5"PRId16" Cb: %+5"PRId16" Cr: %+5"PRId16"\n", YCbCr[0], YCbCr[1], YCbCr[2]);
//printf("[0]: %20.20lf\n", coeffs[0]);
//printf("[1]: %20.20lf\n", coeffs[1]);
//printf("[2]: %20.20lf\n", coeffs[2]);
//printf("[3]: %20.20lf\n", coeffs[3]);
printf("--------------------------------\n\n");
return 0;
}
int test_YCbCr_pixels()
{
if (0)
{
test_YCbCr_fp(TEST_YCbCrToRGB_01, TEST_YCbCr_01, TEST_RGB_01);
test_YCbCr_fp(TEST_YCbCrToRGB_01, TEST_YCbCr_02, TEST_RGB_02);
test_YCbCr_fp(TEST_YCbCrToRGB_01, TEST_YCbCr_03, TEST_RGB_03);
}
if (1)
{
test_YCbCr_fp(TEST_YCbCrToRGB_02, TEST_YCbCr_01, TEST_RGB_01);
test_YCbCr_fp(TEST_YCbCrToRGB_02, TEST_YCbCr_02, TEST_RGB_02);
test_YCbCr_fp(TEST_YCbCrToRGB_02, TEST_YCbCr_03, TEST_RGB_03);
}
if (0)
{
test_YCbCr_fp(TEST_YCbCrToRGB_03, TEST_YCbCr_01, TEST_RGB_01);
test_YCbCr_fp(TEST_YCbCrToRGB_03, TEST_YCbCr_02, TEST_RGB_02);
test_YCbCr_fp(TEST_YCbCrToRGB_03, TEST_YCbCr_03, TEST_RGB_03);
}
return 0;
}
int TestPrimitivesYCbCr(int argc, char* argv[])
{
pstatus_t status = PRIMITIVES_SUCCESS;
int size;
pstatus_t status = -1;
int cnt[3];
float err[3];
BYTE* actual;
BYTE* expected;
int margin = 1;
INT16* pYCbCr[3];
const primitives_t* prims = primitives_get();
static const prim_size_t roi_64x64 = { 64, 64 };
const INT16* pYCbCr[3];
const UINT32 srcStride = roi.width * 2;
const UINT32 dstStride = roi.width * GetBytesPerPixel(format);
const UINT32 srcSize = srcStride * roi.height;
const UINT32 dstSize = dstStride * roi.height;
PROFILER_DEFINE(prof);
//return test_YCbCr_pixels();
expected = (BYTE*) TEST_XRGB_IMAGE;
size = 64 * 64 * 4;
actual = _aligned_malloc(size, 16);
actual = _aligned_malloc(dstSize, 16);
PROFILER_CREATE(prof, "YCbCr");
if (!actual)
return 1;
goto fail;
ZeroMemory(actual, size);
ZeroMemory(actual, dstSize);
pYCbCr[0] = TEST_Y_COMPONENT;
pYCbCr[1] = TEST_CB_COMPONENT;
pYCbCr[2] = TEST_CR_COMPONENT;
if (1)
{
status = prims->yCbCrToRGB_16s8u_P3AC4R((const INT16**) pYCbCr, 64 * 2,
actual, 64 * 4, PIXEL_FORMAT_BGRA32,
&roi_64x64);
PROFILER_ENTER(prof);
status = prims->yCbCrToRGB_16s8u_P3AC4R((const INT16**) pYCbCr, srcStride,
actual, dstStride, format,
&roi);
PROFILER_EXIT(prof);
}
else
{
INT16* pSrcDst[3];
pSrcDst[0] = _aligned_malloc(4096 * 2, 16);
pSrcDst[1] = _aligned_malloc(4096 * 2, 16);
pSrcDst[2] = _aligned_malloc(4096 * 2, 16);
CopyMemory(pSrcDst[0], pYCbCr[0], 4096 * 2);
CopyMemory(pSrcDst[1], pYCbCr[1], 4096 * 2);
CopyMemory(pSrcDst[2], pYCbCr[2], 4096 * 2);
prims->yCbCrToRGB_16s16s_P3P3((const INT16**) pSrcDst, 64 * 2,
pSrcDst, 64 * 2, &roi_64x64);
prims->RGBToRGB_16s8u_P3AC4R((const INT16**) pSrcDst, 64 * 2,
actual, 64 * 4, PIXEL_FORMAT_BGRA32, &roi_64x64);
pSrcDst[0] = _aligned_malloc(srcSize, 16);
pSrcDst[1] = _aligned_malloc(srcSize, 16);
pSrcDst[2] = _aligned_malloc(srcSize, 16);
CopyMemory(pSrcDst[0], pYCbCr[0], srcSize);
CopyMemory(pSrcDst[1], pYCbCr[1], srcSize);
CopyMemory(pSrcDst[2], pYCbCr[2], srcSize);
PROFILER_ENTER(prof);
status = prims->yCbCrToRGB_16s16s_P3P3((const INT16**) pSrcDst, srcStride,
pSrcDst, srcStride, &roi);
if (status != PRIMITIVES_SUCCESS)
goto fail2;
status = prims->RGBToRGB_16s8u_P3AC4R((const INT16**) pSrcDst, srcStride,
actual, dstStride, format, &roi);
PROFILER_EXIT(prof);
fail2:
_aligned_free(pSrcDst[0]);
_aligned_free(pSrcDst[1]);
_aligned_free(pSrcDst[2]);
if (status != PRIMITIVES_SUCCESS)
goto fail;
}
if (0)
{
test_fill_bitmap_channel(actual, 64, 64, 0, 2); /* red */
test_fill_bitmap_channel(expected, 64, 64, 0, 2); /* red */
}
if (0)
{
test_fill_bitmap_channel(actual, 64, 64, 0, 1); /* green */
test_fill_bitmap_channel(expected, 64, 64, 0, 1); /* green */
}
if (0)
{
test_fill_bitmap_channel(actual, 64, 64, 0, 0); /* blue */
test_fill_bitmap_channel(expected, 64, 64, 0, 0); /* blue */
}
cnt[2] = test_bmp_cmp_count(actual, expected, size, 2, margin); /* red */
err[2] = ((float) cnt[2]) / ((float) size / 4) * 100.0f;
cnt[1] = test_bmp_cmp_count(actual, expected, size, 1, margin); /* green */
err[1] = ((float) cnt[1]) / ((float) size / 4) * 100.0f;
cnt[0] = test_bmp_cmp_count(actual, expected, size, 0, margin); /* blue */
err[0] = ((float) cnt[0]) / ((float) size / 4) * 100.0f;
cnt[2] = test_bmp_cmp_count(actual, expected, dstSize, 2, margin); /* red */
err[2] = ((float) cnt[2]) / ((float) dstSize / 4) * 100.0f;
cnt[1] = test_bmp_cmp_count(actual, expected, dstSize, 1, margin); /* green */
err[1] = ((float) cnt[1]) / ((float) dstSize / 4) * 100.0f;
cnt[0] = test_bmp_cmp_count(actual, expected, dstSize, 0, margin); /* blue */
err[0] = ((float) cnt[0]) / ((float) dstSize / 4) * 100.0f;
if (cnt[0] || cnt[1] || cnt[2])
{
printf("Red Error Dump:\n");
test_bmp_cmp_dump(actual, expected, size, 2, margin); /* red */
test_bmp_cmp_dump(actual, expected, dstSize, 2, margin); /* red */
printf("Green Error Dump:\n");
test_bmp_cmp_dump(actual, expected, size, 1, margin); /* green */
test_bmp_cmp_dump(actual, expected, dstSize, 1, margin); /* green */
printf("Blue Error Dump:\n");
test_bmp_cmp_dump(actual, expected, size, 0, margin); /* blue */
test_bmp_cmp_dump(actual, expected, dstSize, 0, margin); /* blue */
printf("R: diff: %d (%f%%)\n", cnt[2], err[2]);
printf("G: diff: %d (%f%%)\n", cnt[1], err[1]);
printf("B: diff: %d (%f%%)\n", cnt[0], err[0]);
}
PROFILER_PRINT(prof);
fail:
_aligned_free(actual);
return (status == PRIMITIVES_SUCCESS) ? 0 : 1;
PROFILER_FREE(prof);
return status;
}
int TestPrimitivesYCbCr(int argc, char* argv[])
{
const UINT32 formats[] =
{
PIXEL_FORMAT_XRGB32,
PIXEL_FORMAT_XBGR32,
PIXEL_FORMAT_ARGB32,
PIXEL_FORMAT_ABGR32,
PIXEL_FORMAT_RGBA32,
PIXEL_FORMAT_RGBX32,
PIXEL_FORMAT_BGRA32,
PIXEL_FORMAT_BGRX32
};
const primitives_t* prims = primitives_get();
const primitives_t* generics = primitives_get_generic();
prim_size_t roi = { 64, 64 };
UINT32 x;
for (x = 0; x < sizeof(formats) / sizeof(formats[0]); x++)
{
int rc;
printf("----------------------- GENERIC %s -------------------\n",
GetColorFormatName(formats[x]));
rc = test_PrimitivesYCbCr(generics, formats[x], roi);
if (rc != PRIMITIVES_SUCCESS)
return rc;
printf("------------------------- END %s ----------------------\n",
GetColorFormatName(formats[x]));
printf("---------------------- OPTIMIZED %s -------------------\n",
GetColorFormatName(formats[x]));
rc = test_PrimitivesYCbCr(prims, formats[x], roi);
if (rc != PRIMITIVES_SUCCESS)
return rc;
printf("------------------------- END %s ----------------------\n",
GetColorFormatName(formats[x]));
}
return 0;
}

View File

@ -22,18 +22,20 @@
#include <winpr/sysinfo.h>
#include "prim_test.h"
#include <freerdp/utils/profiler.h>
/* ------------------------------------------------------------------------- */
static BOOL test_YCoCgRToRGB_8u_AC4R_func(void)
static BOOL test_YCoCgRToRGB_8u_AC4R_func(UINT32 width, UINT32 height)
{
BOOL result = TRUE;
pstatus_t status;
INT32 ALIGN(out_sse[4098]), ALIGN(out_sse_inv[4098]);
INT32 ALIGN(in[4098]);
INT32 ALIGN(out_c[4098]), ALIGN(out_c_inv[4098]);
BYTE* out_sse = NULL;
BYTE* in = NULL;
BYTE* out_c = NULL;
UINT32 i, x;
const UINT32 formats[] = {
const UINT32 srcStride = width * 4;
const UINT32 size = srcStride * height;
const UINT32 formats[] =
{
PIXEL_FORMAT_ARGB32,
PIXEL_FORMAT_ABGR32,
PIXEL_FORMAT_RGBA32,
@ -41,86 +43,77 @@ static BOOL test_YCoCgRToRGB_8u_AC4R_func(void)
PIXEL_FORMAT_BGRA32,
PIXEL_FORMAT_BGRX32
};
PROFILER_DEFINE(genericProf);
PROFILER_DEFINE(optProf);
PROFILER_CREATE(genericProf, "YCoCgRToRGB_8u_AC4R-GENERIC");
PROFILER_CREATE(optProf, "YCoCgRToRGB_8u_AC4R-OPT");
in = _aligned_malloc(size, 16);
out_c = _aligned_malloc(size, 16);
out_sse = _aligned_malloc(size, 16);
winpr_RAND((BYTE*)in, sizeof(in));
if (!in || !out_c || !out_sse)
goto fail;
for (x=0; x<sizeof(formats)/sizeof(formats[0]); x++)
winpr_RAND(in, sizeof(in));
for (x = 0; x < sizeof(formats) / sizeof(formats[0]); x++)
{
UINT32 format = formats[x];
const UINT32 format = formats[x];
const UINT32 dstStride = width * GetBytesPerPixel(format);
const char* formatName = GetColorFormatName(format);
PROFILER_ENTER(genericProf);
status = generic->YCoCgToRGB_8u_AC4R(
(const BYTE*)(in + 1), 63 * 4,
(BYTE*) out_c, format, 63 * 4, 63, 61, 2, TRUE);
if (status != PRIMITIVES_SUCCESS)
return FALSE;
status = generic->YCoCgToRGB_8u_AC4R(
(const BYTE*)(in + 1), 63 * 4,
(BYTE*) out_c_inv, format, 63 * 4, 63, 61, 2, TRUE);
if (status != PRIMITIVES_SUCCESS)
return FALSE;
in, srcStride,
out_c, format, dstStride, width, height, 2, TRUE);
PROFILER_EXIT(genericProf);
status = optimized->YCoCgToRGB_8u_AC4R(
(const BYTE*)(in + 1), 63 * 4,
(BYTE*) out_sse, format, 63 * 4, 63, 61, 2, TRUE);
if (status != PRIMITIVES_SUCCESS)
return FALSE;
status = optimized->YCoCgToRGB_8u_AC4R(
(const BYTE*)(in + 1), 63 * 4,
(BYTE*) out_sse_inv, format, 63 * 4, 63, 61, 2, TRUE);
if (status != PRIMITIVES_SUCCESS)
return FALSE;
goto fail;
for (i = 0; i < 63 * 61; ++i)
PROFILER_ENTER(optProf);
status = optimized->YCoCgToRGB_8u_AC4R(
in, srcStride,
out_sse, format, dstStride, width, height, 2, TRUE);
PROFILER_EXIT(optProf);
if (status != PRIMITIVES_SUCCESS)
goto fail;
if (memcmp(out_c, out_sse, dstStride * height) != 0)
{
if (out_c[i] != out_sse[i])
for (i = 0; i < width * height; ++i)
{
printf("optimized->YCoCgRToRGB FAIL[%"PRIu32"]: 0x%08"PRIx32" -> C 0x%08"PRIx32" vs optimized 0x%08"PRIx32"\n",
i, in[i + 1], out_c[i], out_sse[i]);
result = FALSE;
const UINT32 c = ReadColor(out_c + 4 * i, format);
const UINT32 sse = ReadColor(out_sse + 4 * i, format);
if (c != sse)
{
printf("optimized->YCoCgRToRGB FAIL[%s] [%"PRIu32"]: 0x%08"PRIx32" -> C 0x%08"PRIx32" vs optimized 0x%08"PRIx32"\n",
formatName, i, in[i + 1], c, sse);
status = -1;
}
}
}
for (i = 0; i < 63 * 61; ++i)
{
if (out_c_inv[i] != out_sse_inv[i])
{
printf("optimized->YCoCgRToRGB inverted FAIL[%"PRIu32"]: 0x%08"PRIu32" -> C 0x%08"PRIx32" vs optimized 0x%08"PRIx32"\n",
i, in[i + 1], out_c_inv[i], out_sse_inv[i]);
result = FALSE;
}
}
PROFILER_PRINT(genericProf);
PROFILER_PRINT(optProf);
}
return result;
}
static int test_YCoCgRToRGB_8u_AC4R_speed(void)
{
INT32 ALIGN(in[4096]);
INT32 ALIGN(out[4096]);
winpr_RAND((BYTE*)in, sizeof(in));
if (!speed_test("YCoCgToRGB_8u_AC4R", "aligned", g_Iterations,
(speed_test_fkt)generic->YCoCgToRGB_8u_AC4R,
(speed_test_fkt)optimized->YCoCgToRGB_8u_AC4R,
in, 64 * 4, out, 64 * 4, 64, 64, 2, FALSE, FALSE))
return FALSE;
return TRUE;
fail:
PROFILER_FREE(genericProf);
PROFILER_FREE(optProf);
_aligned_free(in);
_aligned_free(out_c);
_aligned_free(out_sse);
return status == PRIMITIVES_SUCCESS;
}
int TestPrimitivesYCoCg(int argc, char* argv[])
{
prim_test_setup(FALSE);
if (!test_YCoCgRToRGB_8u_AC4R_func())
if (!test_YCoCgRToRGB_8u_AC4R_func(1920, 1080))
return 1;
if (g_TestPrimitivesPerformance)
{
if (!test_YCoCgRToRGB_8u_AC4R_speed())
return 1;
}
return 0;
}

View File

@ -22,7 +22,7 @@ static BOOL similar(const BYTE* src, const BYTE* dst, size_t size)
{
int diff = src[x] - dst[x];
if (abs(diff) > 2)
if (abs(diff) > 4)
{
fprintf(stderr, "%"PRIuz" %02"PRIX8" : %02"PRIX8" diff=%d\n", x, src[x], dst[x], abs(diff));
return FALSE;
@ -78,13 +78,14 @@ static BOOL similarRGB(const BYTE* src, const BYTE* dst, size_t size, UINT32 for
return TRUE;
}
static void get_size(UINT32* width, UINT32* height)
static void get_size(BOOL large, UINT32* width, UINT32* height)
{
UINT32 shift = large ? 8 : 1;
winpr_RAND((BYTE*)width, sizeof(*width));
winpr_RAND((BYTE*)height, sizeof(*height));
// TODO: Algorithm only works on even resolutions...
*width = (*width % 64 + 1) << 1;
*height = (*height % 64 + 1) << 1;
*width = (*width % 64 + 1) << shift;
*height = (*height % 64 + 1) << shift;
}
static BOOL check_padding(const BYTE* psrc, size_t size, size_t padding,
@ -170,7 +171,7 @@ static void free_padding(void* src, size_t padding)
/* Create 2 pseudo YUV420 frames of same size.
* Combine them and check, if the data is at the expected position. */
static BOOL TestPrimitiveYUVCombine(void)
static BOOL TestPrimitiveYUVCombine(primitives_t* prims, prim_size_t roi)
{
UINT32 x, y, i;
UINT32 awidth, aheight;
@ -186,9 +187,6 @@ static BOOL TestPrimitiveYUVCombine(void)
size_t padding = 10000;
PROFILER_DEFINE(yuvCombine);
PROFILER_DEFINE(yuvSplit);
prim_size_t roi;
primitives_t* prims = primitives_get();
get_size(&roi.width, &roi.height);
awidth = roi.width + 16 - roi.width % 16;
aheight = roi.height + 16 - roi.height % 16;
fprintf(stderr, "Running YUVCombine on frame size %"PRIu32"x%"PRIu32" [%"PRIu32"x%"PRIu32"]\n",
@ -360,18 +358,16 @@ fail:
return rc;
}
static BOOL TestPrimitiveYUV(BOOL use444)
static BOOL TestPrimitiveYUV(primitives_t* prims, prim_size_t roi, BOOL use444)
{
BOOL rc = FALSE;
UINT32 x, y;
UINT32 awidth, aheight;
BYTE* yuv[3] = {0};
UINT32 yuv_step[3];
prim_size_t roi;
BYTE* rgb = NULL;
BYTE* rgb_dst = NULL;
size_t size;
primitives_t* prims = primitives_get();
size_t uvsize, uvwidth;
size_t padding = 10000;
size_t stride;
@ -390,7 +386,6 @@ static BOOL TestPrimitiveYUV(BOOL use444)
PROFILER_DEFINE(rgbToYUV444);
PROFILER_DEFINE(yuv420ToRGB);
PROFILER_DEFINE(yuv444ToRGB);
get_size(&roi.width, &roi.height);
/* Buffers need to be 16x16 aligned. */
awidth = roi.width + 16 - roi.width % 16;
aheight = roi.height + 16 - roi.height % 16;
@ -457,6 +452,7 @@ static BOOL TestPrimitiveYUV(BOOL use444)
for (x = 0; x < sizeof(formats) / sizeof(formats[0]); x++)
{
const UINT32 DstFormat = formats[x];
printf("Testing destination color format %s\n", GetColorFormatName(DstFormat));
if (use444)
{
@ -561,26 +557,73 @@ fail:
int TestPrimitivesYUV(int argc, char* argv[])
{
BOOL large = (argc > 1);
UINT32 x;
int rc = -1;
prim_test_setup(FALSE);
primitives_t* prims = primitives_get();
primitives_t* generic = primitives_get_generic();
for (x = 0; x < 10; x++)
{
if (!TestPrimitiveYUV(TRUE)) {
prim_size_t roi;
get_size(large, &roi.width, &roi.height);
printf("-------------------- GENERIC ------------------------\n");
if (!TestPrimitiveYUV(generic, roi, TRUE))
{
printf("TestPrimitiveYUV (444) failed.\n");
goto end;
}
if (!TestPrimitiveYUV(FALSE)) {
printf("---------------------- END --------------------------\n");
#if 1
printf("------------------- OPTIMIZED -----------------------\n");
if (!TestPrimitiveYUV(prims, roi, TRUE))
{
printf("TestPrimitiveYUV (444) failed.\n");
goto end;
}
printf("---------------------- END --------------------------\n");
#endif
printf("-------------------- GENERIC ------------------------\n");
if (!TestPrimitiveYUV(generic, roi, FALSE))
{
printf("TestPrimitiveYUV (420) failed.\n");
goto end;
}
if (!TestPrimitiveYUVCombine()) {
printf("---------------------- END --------------------------\n");
printf("------------------- OPTIMIZED -----------------------\n");
if (!TestPrimitiveYUV(prims, roi, FALSE))
{
printf("TestPrimitiveYUV (420) failed.\n");
goto end;
}
printf("---------------------- END --------------------------\n");
printf("-------------------- GENERIC ------------------------\n");
if (!TestPrimitiveYUVCombine(generic, roi))
{
printf("TestPrimitiveYUVCombine failed.\n");
goto end;
}
printf("---------------------- END --------------------------\n");
printf("------------------- OPTIMIZED -----------------------\n");
if (!TestPrimitiveYUVCombine(prims, roi))
{
printf("TestPrimitiveYUVCombine failed.\n");
goto end;
}
printf("---------------------- END --------------------------\n");
}
rc = 0;

View File

@ -110,5 +110,5 @@ if [ ! -d $BUILD_DST/include ];
then
common_run mkdir -p $BUILD_DST/include
fi
common_run cp -L -r $BUILD_SRC/include/openssl $BUILD_DST/include/
common_run cp -L -R $BUILD_SRC/include/openssl $BUILD_DST/include/