зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1672309 - Port remaning gtests to Rust. r=aosmond
I've left the C++ ones for now. Differential Revision: https://phabricator.services.mozilla.com/D94246
This commit is contained in:
Родитель
6fd5944648
Коммит
577c167863
|
@ -1,7 +1,28 @@
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::{
|
||||
iccread::*, transform::*, transform_util::lut_inverse_interp16, QCMS_INTENT_PERCEPTUAL,
|
||||
iccread::*, transform::*, transform_util::lut_inverse_interp16, QCMS_INTENT_DEFAULT,
|
||||
QCMS_INTENT_PERCEPTUAL,
|
||||
};
|
||||
use libc::c_void;
|
||||
use std::ptr::null_mut;
|
||||
|
||||
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
|
||||
use crate::transform_neon::{
|
||||
qcms_transform_data_bgra_out_lut_neon, qcms_transform_data_rgb_out_lut_neon,
|
||||
qcms_transform_data_rgba_out_lut_neon,
|
||||
};
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
use crate::{
|
||||
transform_avx::{
|
||||
qcms_transform_data_bgra_out_lut_avx, qcms_transform_data_rgb_out_lut_avx,
|
||||
qcms_transform_data_rgba_out_lut_avx,
|
||||
},
|
||||
transform_sse2::{
|
||||
qcms_transform_data_bgra_out_lut_sse2, qcms_transform_data_rgb_out_lut_sse2,
|
||||
qcms_transform_data_rgba_out_lut_sse2,
|
||||
},
|
||||
};
|
||||
|
||||
#[test]
|
||||
|
@ -332,4 +353,503 @@ mod test {
|
|||
unsafe { qcms_profile_release(profile) }
|
||||
unsafe { qcms_profile_release(srgb_profile) }
|
||||
}
|
||||
|
||||
fn CmpRgbChannel(reference: &[u8], test: &[u8], index: usize) -> bool {
|
||||
(reference[index] as i32 - test[index] as i32).abs() <= 1
|
||||
}
|
||||
|
||||
fn CmpRgbBufferImpl(
|
||||
refBuffer: &[u8],
|
||||
testBuffer: &[u8],
|
||||
pixels: usize,
|
||||
kSwapRB: bool,
|
||||
hasAlpha: bool,
|
||||
) -> bool {
|
||||
let pixelSize = if hasAlpha { 4 } else { 3 };
|
||||
if refBuffer[..pixels * pixelSize] == testBuffer[..pixels * pixelSize] {
|
||||
return true;
|
||||
}
|
||||
|
||||
let kRIndex = if kSwapRB { 2 } else { 0 };
|
||||
let kGIndex = 1;
|
||||
let kBIndex = if kSwapRB { 0 } else { 2 };
|
||||
let kAIndex = 3;
|
||||
|
||||
let mut remaining = pixels;
|
||||
let mut reference = &refBuffer[..];
|
||||
let mut test = &testBuffer[..];
|
||||
while remaining > 0 {
|
||||
if !CmpRgbChannel(reference, test, kRIndex)
|
||||
|| !CmpRgbChannel(reference, test, kGIndex)
|
||||
|| !CmpRgbChannel(reference, test, kBIndex)
|
||||
|| (hasAlpha && reference[kAIndex] != test[kAIndex])
|
||||
{
|
||||
assert_eq!(test[kRIndex], reference[kRIndex]);
|
||||
assert_eq!(test[kGIndex], reference[kGIndex]);
|
||||
assert_eq!(test[kBIndex], reference[kBIndex]);
|
||||
if hasAlpha {
|
||||
assert_eq!(test[kAIndex], reference[kAIndex]);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
remaining -= 1;
|
||||
reference = &reference[pixelSize..];
|
||||
test = &test[pixelSize..];
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn GetRgbInputBufferImpl(kSwapRB: bool, kHasAlpha: bool) -> (usize, Vec<u8>) {
|
||||
let colorSamples = [0, 5, 16, 43, 101, 127, 182, 255];
|
||||
let colorSampleMax = colorSamples.len();
|
||||
let pixelSize = if kHasAlpha { 4 } else { 3 };
|
||||
let pixelCount = colorSampleMax * colorSampleMax * 256 * 3;
|
||||
|
||||
let mut outBuffer = vec![0; pixelCount * pixelSize];
|
||||
|
||||
let kRIndex = if kSwapRB { 2 } else { 0 };
|
||||
let kGIndex = 1;
|
||||
let kBIndex = if kSwapRB { 0 } else { 2 };
|
||||
let kAIndex = 3;
|
||||
|
||||
// Sample every red pixel value with a subset of green and blue.
|
||||
let mut color = &mut outBuffer[..];
|
||||
for r in 0..=255 {
|
||||
for &g in colorSamples.iter() {
|
||||
for &b in colorSamples.iter() {
|
||||
color[kRIndex] = r;
|
||||
color[kGIndex] = g;
|
||||
color[kBIndex] = b;
|
||||
if kHasAlpha {
|
||||
color[kAIndex] = 0x80;
|
||||
}
|
||||
color = &mut color[pixelSize..];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sample every green pixel value with a subset of red and blue.
|
||||
let mut color = &mut outBuffer[..];
|
||||
for &r in colorSamples.iter() {
|
||||
for g in 0..=255 {
|
||||
for &b in colorSamples.iter() {
|
||||
color[kRIndex] = r;
|
||||
color[kGIndex] = g;
|
||||
color[kBIndex] = b;
|
||||
if kHasAlpha {
|
||||
color[kAIndex] = 0x80;
|
||||
}
|
||||
color = &mut color[pixelSize..];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sample every blue pixel value with a subset of red and green.
|
||||
let mut color = &mut outBuffer[..];
|
||||
for &r in colorSamples.iter() {
|
||||
for &g in colorSamples.iter() {
|
||||
for b in 0..=255 {
|
||||
color[kRIndex] = r;
|
||||
color[kGIndex] = g;
|
||||
color[kBIndex] = b;
|
||||
if kHasAlpha {
|
||||
color[kAIndex] = 0x80;
|
||||
}
|
||||
color = &mut color[pixelSize..];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(pixelCount, outBuffer)
|
||||
}
|
||||
|
||||
fn GetRgbInputBuffer() -> (usize, Vec<u8>) {
|
||||
GetRgbInputBufferImpl(false, false)
|
||||
}
|
||||
|
||||
fn GetRgbaInputBuffer() -> (usize, Vec<u8>) {
|
||||
GetRgbInputBufferImpl(false, true)
|
||||
}
|
||||
|
||||
fn GetBgraInputBuffer() -> (usize, Vec<u8>) {
|
||||
GetRgbInputBufferImpl(true, true)
|
||||
}
|
||||
|
||||
fn CmpRgbBuffer(refBuffer: &[u8], testBuffer: &[u8], pixels: usize) -> bool {
|
||||
CmpRgbBufferImpl(refBuffer, testBuffer, pixels, false, false)
|
||||
}
|
||||
|
||||
fn CmpRgbaBuffer(refBuffer: &[u8], testBuffer: &[u8], pixels: usize) -> bool {
|
||||
CmpRgbBufferImpl(refBuffer, testBuffer, pixels, false, true)
|
||||
}
|
||||
|
||||
fn CmpBgraBuffer(refBuffer: &[u8], testBuffer: &[u8], pixels: usize) -> bool {
|
||||
CmpRgbBufferImpl(refBuffer, testBuffer, pixels, true, true)
|
||||
}
|
||||
|
||||
fn ClearRgbBuffer(buffer: &mut [u8], pixels: usize) {
|
||||
for i in 0..pixels * 3 {
|
||||
buffer[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
fn ClearRgbaBuffer(buffer: &mut [u8], pixels: usize) {
|
||||
for i in 0..pixels * 4 {
|
||||
buffer[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
fn GetRgbOutputBuffer(pixels: usize) -> Vec<u8> {
|
||||
vec![0; pixels * 3]
|
||||
}
|
||||
|
||||
fn GetRgbaOutputBuffer(pixels: usize) -> Vec<u8> {
|
||||
vec![0; pixels * 4]
|
||||
}
|
||||
|
||||
struct QcmsProfileTest {
|
||||
in_profile: *mut qcms_profile,
|
||||
out_profile: *mut qcms_profile,
|
||||
transform: *mut qcms_transform,
|
||||
|
||||
input: Vec<u8>,
|
||||
output: Vec<u8>,
|
||||
reference: Vec<u8>,
|
||||
|
||||
pixels: usize,
|
||||
storage_type: qcms_data_type,
|
||||
precache: bool,
|
||||
}
|
||||
|
||||
impl QcmsProfileTest {
|
||||
fn new() -> QcmsProfileTest {
|
||||
QcmsProfileTest {
|
||||
in_profile: null_mut(),
|
||||
out_profile: null_mut(),
|
||||
transform: null_mut(),
|
||||
input: Vec::new(),
|
||||
output: Vec::new(),
|
||||
reference: Vec::new(),
|
||||
|
||||
pixels: 0,
|
||||
storage_type: QCMS_DATA_RGB_8,
|
||||
precache: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn SetUp(&mut self) {
|
||||
unsafe {
|
||||
qcms_enable_iccv4();
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
unsafe {
|
||||
if is_x86_feature_detected!("avx") {
|
||||
qcms_enable_avx()
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(target_arch = "arm")]
|
||||
unsafe {
|
||||
use crate::transform::qcms_enable_neon;
|
||||
if is_arm_feature_detected!("neon") {
|
||||
qcms_enable_neon()
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
unsafe {
|
||||
use crate::transform::qcms_enable_neon;
|
||||
if is_aarch64_feature_detected!("neon") {
|
||||
qcms_enable_neon()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
unsafe fn TearDown(&mut self) {
|
||||
if self.in_profile != null_mut() {
|
||||
qcms_profile_release(self.in_profile)
|
||||
}
|
||||
|
||||
if self.out_profile != null_mut() {
|
||||
qcms_profile_release(self.out_profile)
|
||||
}
|
||||
|
||||
if self.transform != null_mut() {
|
||||
qcms_transform_release(self.transform)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn SetTransform(&mut self, transform: *mut qcms_transform) -> bool {
|
||||
if self.transform != null_mut() {
|
||||
qcms_transform_release(self.transform)
|
||||
}
|
||||
self.transform = transform;
|
||||
!(self.transform == null_mut())
|
||||
}
|
||||
|
||||
unsafe fn SetTransformForType(&mut self, ty: qcms_data_type) -> bool {
|
||||
self.SetTransform(qcms_transform_create(
|
||||
self.in_profile,
|
||||
ty,
|
||||
self.out_profile,
|
||||
ty,
|
||||
QCMS_INTENT_DEFAULT,
|
||||
))
|
||||
}
|
||||
|
||||
unsafe fn SetBuffers(&mut self, ty: qcms_data_type) -> bool {
|
||||
match ty {
|
||||
QCMS_DATA_RGB_8 => {
|
||||
let (pixels, input) = GetRgbInputBuffer();
|
||||
self.input = input;
|
||||
self.pixels = pixels;
|
||||
self.reference = GetRgbOutputBuffer(self.pixels);
|
||||
self.output = GetRgbOutputBuffer(self.pixels)
|
||||
}
|
||||
QCMS_DATA_RGBA_8 => {
|
||||
let (pixels, input) = GetBgraInputBuffer();
|
||||
self.input = input;
|
||||
self.pixels = pixels;
|
||||
self.reference = GetRgbaOutputBuffer(self.pixels);
|
||||
self.output = GetRgbaOutputBuffer(self.pixels);
|
||||
}
|
||||
QCMS_DATA_BGRA_8 => {
|
||||
let (pixels, input) = GetRgbaInputBuffer();
|
||||
self.input = input;
|
||||
self.pixels = pixels;
|
||||
self.reference = GetRgbaOutputBuffer(self.pixels);
|
||||
self.output = GetRgbaOutputBuffer(self.pixels);
|
||||
}
|
||||
_ => unreachable!("Unknown type!"),
|
||||
}
|
||||
self.storage_type = ty;
|
||||
self.pixels > 0
|
||||
}
|
||||
|
||||
unsafe fn ClearOutputBuffer(&mut self) {
|
||||
match self.storage_type {
|
||||
QCMS_DATA_RGB_8 => ClearRgbBuffer(&mut self.output, self.pixels),
|
||||
QCMS_DATA_RGBA_8 | QCMS_DATA_BGRA_8 => {
|
||||
ClearRgbaBuffer(&mut self.output, self.pixels)
|
||||
}
|
||||
_ => unreachable!("Unknown type!"),
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn ProduceRef(&mut self, trans_fn: transform_fn_t) {
|
||||
trans_fn.unwrap()(
|
||||
self.transform,
|
||||
self.input.as_mut_ptr(),
|
||||
self.reference.as_mut_ptr(),
|
||||
self.pixels,
|
||||
)
|
||||
}
|
||||
|
||||
fn CopyInputToRef(&mut self) {
|
||||
let pixelSize = match self.storage_type {
|
||||
QCMS_DATA_RGB_8 => 3,
|
||||
QCMS_DATA_RGBA_8 | QCMS_DATA_BGRA_8 => 4,
|
||||
_ => unreachable!("Unknown type!"),
|
||||
};
|
||||
self.reference
|
||||
.copy_from_slice(&self.input[..self.pixels * pixelSize])
|
||||
}
|
||||
|
||||
unsafe fn ProduceOutput(&mut self, trans_fn: transform_fn_t) {
|
||||
self.ClearOutputBuffer();
|
||||
trans_fn.unwrap()(
|
||||
self.transform,
|
||||
self.input.as_mut_ptr(),
|
||||
self.output.as_mut_ptr(),
|
||||
self.pixels,
|
||||
)
|
||||
}
|
||||
|
||||
unsafe fn VerifyOutput(&self, buf: &[u8]) -> bool {
|
||||
match self.storage_type {
|
||||
QCMS_DATA_RGB_8 => return CmpRgbBuffer(buf, &self.output, self.pixels),
|
||||
QCMS_DATA_RGBA_8 => return CmpRgbaBuffer(buf, &self.output, self.pixels),
|
||||
QCMS_DATA_BGRA_8 => return CmpBgraBuffer(buf, &self.output, self.pixels),
|
||||
_ => unreachable!("Unknown type!"),
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn ProduceVerifyOutput(&mut self, trans_fn: transform_fn_t) -> bool {
|
||||
self.ProduceOutput(trans_fn);
|
||||
return self.VerifyOutput(&self.reference);
|
||||
}
|
||||
|
||||
unsafe fn PrecacheOutput(&mut self) {
|
||||
qcms_profile_precache_output_transform(self.out_profile);
|
||||
self.precache = true;
|
||||
}
|
||||
unsafe fn TransformPrecache(&mut self) {
|
||||
assert_eq!(self.precache, false);
|
||||
assert!(self.SetBuffers(QCMS_DATA_RGB_8));
|
||||
assert!(self.SetTransformForType(QCMS_DATA_RGB_8));
|
||||
self.ProduceRef(Some(qcms_transform_data_rgb_out_lut));
|
||||
|
||||
self.PrecacheOutput();
|
||||
assert!(self.SetTransformForType(QCMS_DATA_RGB_8));
|
||||
assert!(self.ProduceVerifyOutput(Some(qcms_transform_data_rgb_out_lut_precache)))
|
||||
}
|
||||
|
||||
unsafe fn TransformPrecachePlatformExt(&mut self) {
|
||||
self.PrecacheOutput();
|
||||
|
||||
// Verify RGB transforms.
|
||||
assert!(self.SetBuffers(QCMS_DATA_RGB_8));
|
||||
assert!(self.SetTransformForType(QCMS_DATA_RGB_8));
|
||||
self.ProduceRef(Some(qcms_transform_data_rgb_out_lut_precache));
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
{
|
||||
assert!(self.ProduceVerifyOutput(Some(qcms_transform_data_rgb_out_lut_sse2)));
|
||||
if is_x86_feature_detected!("avx") {
|
||||
assert!(self.ProduceVerifyOutput(Some(qcms_transform_data_rgb_out_lut_avx)))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "arm")]
|
||||
{
|
||||
if is_arm_feature_detected!("neon") {
|
||||
assert!(self.ProduceVerifyOutput(qcms_transform_data_rgb_out_lut_neon))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
{
|
||||
if is_aarch64_feature_detected!("neon") {
|
||||
assert!(self.ProduceVerifyOutput(qcms_transform_data_rgb_out_lut_neon))
|
||||
}
|
||||
}
|
||||
|
||||
// Verify RGBA transform.
|
||||
assert!(self.SetBuffers(QCMS_DATA_RGBA_8));
|
||||
assert!(self.SetTransformForType(QCMS_DATA_RGBA_8));
|
||||
self.ProduceRef(Some(qcms_transform_data_rgba_out_lut_precache));
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
{
|
||||
assert!(self.ProduceVerifyOutput(Some(qcms_transform_data_rgba_out_lut_sse2)));
|
||||
if is_x86_feature_detected!("avx") {
|
||||
assert!(self.ProduceVerifyOutput(Some(qcms_transform_data_rgba_out_lut_avx)))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "arm")]
|
||||
{
|
||||
if is_arm_feature_detected!("neon") {
|
||||
assert!(self.ProduceVerifyOutput(Some(qcms_transform_data_rgba_out_lut_neon)))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
{
|
||||
if is_aarch64_feature_detected!("neon") {
|
||||
assert!(self.ProduceVerifyOutput(Some(qcms_transform_data_rgba_out_lut_neon)))
|
||||
}
|
||||
}
|
||||
|
||||
// Verify BGRA transform.
|
||||
assert!(self.SetBuffers(QCMS_DATA_BGRA_8));
|
||||
assert!(self.SetTransformForType(QCMS_DATA_BGRA_8));
|
||||
self.ProduceRef(Some(qcms_transform_data_bgra_out_lut_precache));
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
{
|
||||
assert!(self.ProduceVerifyOutput(Some(qcms_transform_data_bgra_out_lut_sse2)));
|
||||
if is_x86_feature_detected!("avx") {
|
||||
assert!(self.ProduceVerifyOutput(Some(qcms_transform_data_bgra_out_lut_avx)))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "arm")]
|
||||
{
|
||||
if is_arm_feature_detected!("neon") {
|
||||
assert!(self.ProduceVerifyOutput(Some(qcms_transform_data_bgra_out_lut_neon)))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
{
|
||||
if is_aarch64_feature_detected!("neon") {
|
||||
assert!(self.ProduceVerifyOutput(Some(qcms_transform_data_bgra_out_lut_neon)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sRGB_to_sRGB_precache() {
|
||||
unsafe {
|
||||
let mut pt = QcmsProfileTest::new();
|
||||
pt.SetUp();
|
||||
pt.in_profile = qcms_profile_sRGB();
|
||||
pt.out_profile = qcms_profile_sRGB();
|
||||
pt.TransformPrecache();
|
||||
pt.TearDown();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sRGB_to_sRGB_transform_identity() {
|
||||
unsafe {
|
||||
let mut pt = QcmsProfileTest::new();
|
||||
pt.SetUp();
|
||||
pt.in_profile = qcms_profile_sRGB();
|
||||
pt.out_profile = qcms_profile_sRGB();
|
||||
pt.PrecacheOutput();
|
||||
pt.SetBuffers(QCMS_DATA_RGB_8);
|
||||
pt.SetTransformForType(QCMS_DATA_RGB_8);
|
||||
qcms_transform_data(
|
||||
pt.transform,
|
||||
pt.input.as_mut_ptr() as *mut c_void,
|
||||
pt.output.as_mut_ptr() as *mut c_void,
|
||||
pt.pixels,
|
||||
);
|
||||
assert!(pt.VerifyOutput(&pt.input));
|
||||
pt.TearDown();
|
||||
}
|
||||
}
|
||||
|
||||
fn profile_from_path(file: &str) -> *mut qcms_profile {
|
||||
use std::io::Read;
|
||||
let mut path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
path.push("profiles");
|
||||
path.push(file);
|
||||
let mut file = std::fs::File::open(path).unwrap();
|
||||
let mut data = Vec::new();
|
||||
file.read_to_end(&mut data).unwrap();
|
||||
let profile =
|
||||
unsafe { qcms_profile_from_memory(data.as_ptr() as *const c_void, data.len()) };
|
||||
assert_ne!(profile, std::ptr::null_mut());
|
||||
profile
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sRGB_to_ThinkpadW540() {
|
||||
unsafe {
|
||||
let mut pt = QcmsProfileTest::new();
|
||||
pt.SetUp();
|
||||
pt.in_profile = qcms_profile_sRGB();
|
||||
pt.out_profile = profile_from_path("lcms_thinkpad_w540.icc");
|
||||
pt.TransformPrecachePlatformExt();
|
||||
pt.TearDown();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sRGB_to_SamsungSyncmaster() {
|
||||
unsafe {
|
||||
let mut pt = QcmsProfileTest::new();
|
||||
pt.SetUp();
|
||||
pt.in_profile = qcms_profile_sRGB();
|
||||
pt.out_profile = profile_from_path("lcms_samsung_syncmaster.icc");
|
||||
pt.TransformPrecachePlatformExt();
|
||||
pt.TearDown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,8 +68,8 @@ SOURCES += [
|
|||
# notice embedded in the profiles should be reviewed to ensure there are
|
||||
# no known restrictions on distribution.
|
||||
TEST_HARNESS_FILES.gtest += [
|
||||
"icc_profiles/lcms_samsung_syncmaster.icc",
|
||||
"icc_profiles/lcms_thinkpad_w540.icc",
|
||||
"../../qcms/profiles/lcms_samsung_syncmaster.icc",
|
||||
"../../qcms/profiles/lcms_thinkpad_w540.icc",
|
||||
]
|
||||
|
||||
include("/ipc/chromium/chromium-config.mozbuild")
|
||||
|
|
Загрузка…
Ссылка в новой задаче