Merge pull request #3754 from akallabeth/asm3
NEON and SSSE3 decoder optimisations
This commit is contained in:
commit
e97c4b57a4
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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/
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user