mirror of
https://chromium.googlesource.com/libyuv/libyuv
synced 2026-07-31 00:36:32 +08:00
I010ToNV12: dispatch Convert16To8Row on halfwidth
The Convert16To8Row function pointer in I010ToNV12 is only ever called with halfwidth for the chroma planes (the Y plane goes through Convert16To8Plane which has its own dispatch), but its SIMD variants were selected based on the alignment of the full luma width. When width is a multiple of 32 but halfwidth is not, the bare AVX2 kernel was selected and over-read the chroma sources and over-wrote the temporary row buffer. Match the MergeUVRow dispatch in the same function and key on halfwidth. Add a regression test that places the chroma sources against an inaccessible page so the previous over-read faults on AVX2 hardware. Bug: chromium:514748734 Change-Id: I4c2a42857828cdcc6505ebaa65d5b6a95b0f7e55
This commit is contained in:
parent
d23308a2a7
commit
b3928156df
@ -682,7 +682,7 @@ int I010ToNV12(const uint16_t* src_y,
|
||||
#if defined(HAS_CONVERT16TO8ROW_NEON)
|
||||
if (TestCpuFlag(kCpuHasNEON)) {
|
||||
Convert16To8Row = Convert16To8Row_Any_NEON;
|
||||
if (IS_ALIGNED(width, 16)) {
|
||||
if (IS_ALIGNED(halfwidth, 16)) {
|
||||
Convert16To8Row = Convert16To8Row_NEON;
|
||||
}
|
||||
}
|
||||
@ -695,7 +695,7 @@ int I010ToNV12(const uint16_t* src_y,
|
||||
#if defined(HAS_CONVERT16TO8ROW_SSSE3)
|
||||
if (TestCpuFlag(kCpuHasSSSE3)) {
|
||||
Convert16To8Row = Convert16To8Row_Any_SSSE3;
|
||||
if (IS_ALIGNED(width, 16)) {
|
||||
if (IS_ALIGNED(halfwidth, 16)) {
|
||||
Convert16To8Row = Convert16To8Row_SSSE3;
|
||||
}
|
||||
}
|
||||
@ -703,7 +703,7 @@ int I010ToNV12(const uint16_t* src_y,
|
||||
#if defined(HAS_CONVERT16TO8ROW_AVX2)
|
||||
if (TestCpuFlag(kCpuHasAVX2)) {
|
||||
Convert16To8Row = Convert16To8Row_Any_AVX2;
|
||||
if (IS_ALIGNED(width, 32)) {
|
||||
if (IS_ALIGNED(halfwidth, 32)) {
|
||||
Convert16To8Row = Convert16To8Row_AVX2;
|
||||
}
|
||||
}
|
||||
@ -711,7 +711,7 @@ int I010ToNV12(const uint16_t* src_y,
|
||||
#if defined(HAS_CONVERT16TO8ROW_AVX512BW)
|
||||
if (TestCpuFlag(kCpuHasAVX512BW)) {
|
||||
Convert16To8Row = Convert16To8Row_Any_AVX512BW;
|
||||
if (IS_ALIGNED(width, 64)) {
|
||||
if (IS_ALIGNED(halfwidth, 64)) {
|
||||
Convert16To8Row = Convert16To8Row_AVX512BW;
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,6 +12,11 @@
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "libyuv/basic_types.h"
|
||||
#include "libyuv/compare.h"
|
||||
#include "libyuv/convert.h"
|
||||
@ -456,6 +461,80 @@ TESTPLANARTOBP(I210, uint16_t, 2, 2, 1, P210, uint16_t, 2, 2, 1, 10)
|
||||
TESTPLANARTOBP(I012, uint16_t, 2, 2, 2, P012, uint16_t, 2, 2, 2, 12)
|
||||
TESTPLANARTOBP(I212, uint16_t, 2, 2, 1, P212, uint16_t, 2, 2, 1, 12)
|
||||
|
||||
#if defined(__linux__)
|
||||
// I010ToNV12 with a width whose chroma half-width is not a multiple of 32. The
|
||||
// source chroma planes are placed against an inaccessible page so any access
|
||||
// past the last row faults.
|
||||
TEST_F(LibYUVConvertTest, I010ToNV12HalfWidth) {
|
||||
const int kWidth = 96;
|
||||
const int kHeight = 2;
|
||||
const int kHalfWidth = (kWidth + 1) / 2;
|
||||
const int kHalfHeight = (kHeight + 1) / 2;
|
||||
const long kPage = sysconf(_SC_PAGESIZE);
|
||||
const int kUVSize =
|
||||
kHalfWidth * kHalfHeight * static_cast<int>(sizeof(uint16_t));
|
||||
ASSERT_LE(kUVSize, kPage);
|
||||
|
||||
align_buffer_page_end(src_y,
|
||||
kWidth * kHeight * static_cast<int>(sizeof(uint16_t)));
|
||||
align_buffer_page_end(dst_y_c, kWidth * kHeight);
|
||||
align_buffer_page_end(dst_uv_c, kHalfWidth * kHalfHeight * 2);
|
||||
align_buffer_page_end(dst_y_opt, kWidth * kHeight);
|
||||
align_buffer_page_end(dst_uv_opt, kHalfWidth * kHalfHeight * 2);
|
||||
uint8_t* src_u_mem =
|
||||
static_cast<uint8_t*>(mmap(NULL, kPage * 2, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
|
||||
uint8_t* src_v_mem =
|
||||
static_cast<uint8_t*>(mmap(NULL, kPage * 2, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
|
||||
ASSERT_NE(MAP_FAILED, src_u_mem);
|
||||
ASSERT_NE(MAP_FAILED, src_v_mem);
|
||||
ASSERT_EQ(0, mprotect(src_u_mem + kPage, kPage, PROT_NONE));
|
||||
ASSERT_EQ(0, mprotect(src_v_mem + kPage, kPage, PROT_NONE));
|
||||
uint16_t* src_y_p = reinterpret_cast<uint16_t*>(src_y);
|
||||
uint16_t* src_u_p = reinterpret_cast<uint16_t*>(src_u_mem + kPage - kUVSize);
|
||||
uint16_t* src_v_p = reinterpret_cast<uint16_t*>(src_v_mem + kPage - kUVSize);
|
||||
|
||||
MemRandomize(src_y, kWidth * kHeight * static_cast<int>(sizeof(uint16_t)));
|
||||
MemRandomize(reinterpret_cast<uint8_t*>(src_u_p), kUVSize);
|
||||
MemRandomize(reinterpret_cast<uint8_t*>(src_v_p), kUVSize);
|
||||
for (int i = 0; i < kWidth * kHeight; ++i) {
|
||||
src_y_p[i] &= 0x3ff;
|
||||
}
|
||||
for (int i = 0; i < kHalfWidth * kHalfHeight; ++i) {
|
||||
src_u_p[i] &= 0x3ff;
|
||||
src_v_p[i] &= 0x3ff;
|
||||
}
|
||||
memset(dst_y_c, 1, kWidth * kHeight);
|
||||
memset(dst_uv_c, 2, kHalfWidth * kHalfHeight * 2);
|
||||
memset(dst_y_opt, 101, kWidth * kHeight);
|
||||
memset(dst_uv_opt, 102, kHalfWidth * kHalfHeight * 2);
|
||||
|
||||
MaskCpuFlags(disable_cpu_flags_);
|
||||
I010ToNV12(src_y_p, kWidth, src_u_p, kHalfWidth, src_v_p, kHalfWidth, dst_y_c,
|
||||
kWidth, dst_uv_c, kHalfWidth * 2, kWidth, kHeight);
|
||||
MaskCpuFlags(benchmark_cpu_info_);
|
||||
for (int i = 0; i < benchmark_iterations_; ++i) {
|
||||
I010ToNV12(src_y_p, kWidth, src_u_p, kHalfWidth, src_v_p, kHalfWidth,
|
||||
dst_y_opt, kWidth, dst_uv_opt, kHalfWidth * 2, kWidth, kHeight);
|
||||
}
|
||||
for (int i = 0; i < kWidth * kHeight; ++i) {
|
||||
ASSERT_EQ(dst_y_c[i], dst_y_opt[i]);
|
||||
}
|
||||
for (int i = 0; i < kHalfWidth * kHalfHeight * 2; ++i) {
|
||||
ASSERT_EQ(dst_uv_c[i], dst_uv_opt[i]);
|
||||
}
|
||||
|
||||
munmap(src_u_mem, kPage * 2);
|
||||
munmap(src_v_mem, kPage * 2);
|
||||
free_aligned_buffer_page_end(src_y);
|
||||
free_aligned_buffer_page_end(dst_y_c);
|
||||
free_aligned_buffer_page_end(dst_uv_c);
|
||||
free_aligned_buffer_page_end(dst_y_opt);
|
||||
free_aligned_buffer_page_end(dst_uv_opt);
|
||||
}
|
||||
#endif // defined(__linux__)
|
||||
|
||||
#define TESTBPTOBPI(SRC_FMT_PLANAR, SRC_T, SRC_BPC, SRC_SUBSAMP_X, \
|
||||
SRC_SUBSAMP_Y, FMT_PLANAR, DST_T, DST_BPC, DST_SUBSAMP_X, \
|
||||
DST_SUBSAMP_Y, W1280, N, NEG, OFF, DOY, SRC_DEPTH, \
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user