MIPS: Fast path for rgb888 to rgb32 conversion
Add a hand-coded MIPS assembler function to convert a stream of rgb888 bytes to an array of 32-bit ARGB values. This is used in QImage for image conversion, and also in QJpegHandler for decoding JPEG image scanlines. Change-Id: Ia74a5ff799b29fad3d4acbfcafe790cd60586d72 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
bc84e7cd43
commit
8f17d622b0
@ -2176,7 +2176,11 @@ void qInitImageConversions()
|
|||||||
#ifdef QT_COMPILER_SUPPORTS_MIPS_DSPR2
|
#ifdef QT_COMPILER_SUPPORTS_MIPS_DSPR2
|
||||||
extern bool convert_ARGB_to_ARGB_PM_inplace_mips_dspr2(QImageData *data, Qt::ImageConversionFlags);
|
extern bool convert_ARGB_to_ARGB_PM_inplace_mips_dspr2(QImageData *data, Qt::ImageConversionFlags);
|
||||||
inplace_converter_map[QImage::Format_ARGB32][QImage::Format_ARGB32_Premultiplied] = convert_ARGB_to_ARGB_PM_inplace_mips_dspr2;
|
inplace_converter_map[QImage::Format_ARGB32][QImage::Format_ARGB32_Premultiplied] = convert_ARGB_to_ARGB_PM_inplace_mips_dspr2;
|
||||||
return;
|
|
||||||
|
extern void convert_RGB888_to_RGB32_mips_dspr2(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags);
|
||||||
|
qimage_converter_map[QImage::Format::RGB888][QImage::Format_RGB32] = convert_RGB888_to_RGB32_mips_dspr2;
|
||||||
|
qimage_converter_map[QImage::Format::RGB888][QImage::Format_ARGB32] = convert_RGB888_to_RGB32_mips_dspr2;
|
||||||
|
qimage_converter_map[QImage::Format::RGB888][QImage::Format_ARGB32_Premultiplied] = convert_RGB888_to_RGB32_mips_dspr2;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,4 +66,24 @@ bool convert_ARGB_to_ARGB_PM_inplace_mips_dspr2(QImageData *data, Qt::ImageConve
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" void qt_convert_rgb888_to_rgb32_mips_dspr2_asm(uint *dst, const uchar *src, int len);
|
||||||
|
|
||||||
|
void convert_RGB888_to_RGB32_mips_dspr2(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
|
||||||
|
{
|
||||||
|
Q_ASSERT(src->format == QImage::Format_RGB888);
|
||||||
|
Q_ASSERT(dest->format == QImage::Format_RGB32 || dest->format == QImage::Format_ARGB32 || dest->format == QImage::Format_ARGB32_Premultiplied);
|
||||||
|
Q_ASSERT(src->width == dest->width);
|
||||||
|
Q_ASSERT(src->height == dest->height);
|
||||||
|
|
||||||
|
const uchar *src_data = (const uchar*) src->data;
|
||||||
|
quint32 *dest_data = (quint32*) dest->data;
|
||||||
|
|
||||||
|
for (int i = 0; i < src->height; ++i) {
|
||||||
|
qt_convert_rgb888_to_rgb32_mips_dspr2_asm(dest_data, src_data, src->width);
|
||||||
|
src_data += src->bytes_per_line;
|
||||||
|
dest_data = (quint32*) ((uchar*) dest_data + dest->bytes_per_line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
@ -205,3 +205,95 @@ LEAF_MIPS_DSPR2(premultiply_argb_inplace_mips_asm)
|
|||||||
|
|
||||||
END(premultiply_argb_inplace_mips_asm)
|
END(premultiply_argb_inplace_mips_asm)
|
||||||
|
|
||||||
|
|
||||||
|
LEAF_MIPS_DSPR2(qt_convert_rgb888_to_rgb32_mips_dspr2_asm)
|
||||||
|
/*
|
||||||
|
* Parameters:
|
||||||
|
* a0 - dst *a8r8g8b8
|
||||||
|
* a1 - src *r8g8b8
|
||||||
|
* a2 - len
|
||||||
|
*
|
||||||
|
* R G B r g b R G B r g b R G B r g b . . . -- input
|
||||||
|
* ------- ------- ------- ------- -------
|
||||||
|
* _ R G B _ r g b _ R G B _ r g b _ R G . . -- output
|
||||||
|
*
|
||||||
|
* Register usage:
|
||||||
|
* a2 - tail (len % 4) == (len & 0x3)
|
||||||
|
* t0 - batches (len / 4) == (len >> 2)
|
||||||
|
* t1-t7, s1-s3 - temporary
|
||||||
|
*/
|
||||||
|
|
||||||
|
srl t0, a2, 2 /* batches = len / 4 */
|
||||||
|
andi a2, a2, 0x3 /* tail = len % 4 */
|
||||||
|
|
||||||
|
beqz t0, 5f /* if !batches: tail */
|
||||||
|
lui t7, 0xff00 /* [FF 00 00 00] */
|
||||||
|
SAVE_REGS_ON_STACK 8, s1, s2, s3, s0, v0, v1
|
||||||
|
|
||||||
|
1: pref 4, 0 (a1) /* hint: read-streamed */
|
||||||
|
pref 5, 0 (a0) /* hint: prepare-write */
|
||||||
|
addiu t0, t0, -1 /* batches-- */
|
||||||
|
|
||||||
|
lbu t1, 0 (a1) /* [__ __ __ R1] */
|
||||||
|
lbu t2, 1 (a1) /* [__ __ __ G1] */
|
||||||
|
lbu t3, 2 (a1) /* [__ __ __ B1] */
|
||||||
|
|
||||||
|
lbu t4, 3 (a1) /* [__ __ __ r2] */
|
||||||
|
lbu t5, 4 (a1) /* [__ __ __ g2] */
|
||||||
|
lbu t6, 5 (a1) /* [__ __ __ b2] */
|
||||||
|
|
||||||
|
lbu s1, 6 (a1) /* [__ __ __ R3] */
|
||||||
|
lbu s2, 7 (a1) /* [__ __ __ G3] */
|
||||||
|
lbu s3, 8 (a1) /* [__ __ __ B3] */
|
||||||
|
|
||||||
|
lbu s0, 9 (a1) /* [__ __ __ r4] */
|
||||||
|
lbu v0, 10 (a1) /* [__ __ __ g4] */
|
||||||
|
lbu v1, 11 (a1) /* [__ __ __ b4] */
|
||||||
|
|
||||||
|
append t1, t2, 8 /* [__ __ R1 G1] */
|
||||||
|
append t4, t5, 8 /* [__ __ r2 g2] */
|
||||||
|
append s1, s2, 8 /* [__ __ R3 G3] */
|
||||||
|
append s0, v0, 8 /* [__ __ r4 g4] */
|
||||||
|
append t1, t3, 8 /* [__ R1 G1 B1] */
|
||||||
|
append t4, t6, 8 /* [__ r2 g2 b2] */
|
||||||
|
append s1, s3, 8 /* [__ R3 G4 B3] */
|
||||||
|
append s0, v1, 8 /* [__ r4 g4 b4] */
|
||||||
|
or t1, t1, t7 /* [FF R1 G1 B1] */
|
||||||
|
or t4, t4, t7 /* [FF r2 g2 b2] */
|
||||||
|
or s1, s1, t7 /* [FF R3 G3 B3] */
|
||||||
|
or s0, s0, t7 /* [FF r4 g4 b4] */
|
||||||
|
|
||||||
|
sw t1, 0 (a0)
|
||||||
|
sw t4, 4 (a0)
|
||||||
|
sw s1, 8 (a0)
|
||||||
|
sw s0, 12 (a0)
|
||||||
|
|
||||||
|
addiu a1, a1, 12 /* src += 4*3 */
|
||||||
|
bnez t0, 1b /* if batches: loop */
|
||||||
|
addiu a0, a0, 16 /* dst += 4 */
|
||||||
|
|
||||||
|
RESTORE_REGS_FROM_STACK 8, s1, s2, s3, s0, v0, v1
|
||||||
|
|
||||||
|
/* handle remaining "tail" (a2) items */
|
||||||
|
5: beqz a2, 0f
|
||||||
|
lui t0, 0xff00 /* [FF __ __ __] */
|
||||||
|
|
||||||
|
1: lbu t1, 0 (a1) /* [__ __ __ RR] */
|
||||||
|
lbu t2, 1 (a1) /* [__ __ __ GG] */
|
||||||
|
lbu t3, 2 (a1) /* [__ __ __ BB] */
|
||||||
|
sll t1, t1, 16 /* [__ RR __ __] */
|
||||||
|
sll t2, t2, 8 /* [__ __ GG __] */
|
||||||
|
or t0, t0, t1 /* [FF RR __ __] */
|
||||||
|
or t2, t2, t3 /* [__ __ GG BB] */
|
||||||
|
addi a2, a2, -1 /* len-- */
|
||||||
|
or t0, t0, t2 /* [FF RR GG BB] */
|
||||||
|
addiu a1, a1, 3 /* src += 3 */
|
||||||
|
sw t0, 0 (a0)
|
||||||
|
addiu a0, a0, 4 /* dst++ */
|
||||||
|
bnez a2, 1b /* if tail: loop */
|
||||||
|
lui t0, 0xff00 /* [FF __ __ __] */
|
||||||
|
|
||||||
|
0: jr ra
|
||||||
|
nop
|
||||||
|
|
||||||
|
END(qt_convert_rgb888_to_rgb32_mips_dspr2_asm)
|
||||||
|
@ -857,6 +857,7 @@ bool QJpegHandlerPrivate::read(QImage *image)
|
|||||||
Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32_neon(quint32 *dst, const uchar *src, int len);
|
Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32_neon(quint32 *dst, const uchar *src, int len);
|
||||||
Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32_ssse3(quint32 *dst, const uchar *src, int len);
|
Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32_ssse3(quint32 *dst, const uchar *src, int len);
|
||||||
Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32_avx(quint32 *dst, const uchar *src, int len);
|
Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32_avx(quint32 *dst, const uchar *src, int len);
|
||||||
|
extern "C" void qt_convert_rgb888_to_rgb32_mips_dspr2_asm(quint32 *dst, const uchar *src, int len);
|
||||||
|
|
||||||
QJpegHandler::QJpegHandler()
|
QJpegHandler::QJpegHandler()
|
||||||
: d(new QJpegHandlerPrivate(this))
|
: d(new QJpegHandlerPrivate(this))
|
||||||
@ -875,6 +876,9 @@ QJpegHandler::QJpegHandler()
|
|||||||
rgb888ToRgb32ConverterPtr = qt_convert_rgb888_to_rgb32_ssse3;
|
rgb888ToRgb32ConverterPtr = qt_convert_rgb888_to_rgb32_ssse3;
|
||||||
}
|
}
|
||||||
#endif // QT_COMPILER_SUPPORTS_SSSE3
|
#endif // QT_COMPILER_SUPPORTS_SSSE3
|
||||||
|
#if defined(QT_COMPILER_SUPPORTS_MIPS_DSPR2)
|
||||||
|
rgb888ToRgb32ConverterPtr = qt_convert_rgb888_to_rgb32_mips_dspr2_asm;
|
||||||
|
#endif // QT_COMPILER_SUPPORTS_DSPR2
|
||||||
}
|
}
|
||||||
|
|
||||||
QJpegHandler::~QJpegHandler()
|
QJpegHandler::~QJpegHandler()
|
||||||
|
Loading…
Reference in New Issue
Block a user