mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-09 16:51:31 +00:00
[client] tests: cover padded frame strides
Add a configurable stride to the synthetic transport and poison row padding so incorrect row addressing is visible in captured output. Cover full-frame and moving-damage BGRA uploads with 512-byte and 5120-byte pitches, and verify the advertised layout in the log.
This commit is contained in:
@@ -68,6 +68,12 @@ struct DamageCase
|
|||||||
const char * name;
|
const char * name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct StrideCase
|
||||||
|
{
|
||||||
|
const char * name;
|
||||||
|
unsigned stride;
|
||||||
|
};
|
||||||
|
|
||||||
struct Capture
|
struct Capture
|
||||||
{
|
{
|
||||||
LG_TestCaptureHeader header {};
|
LG_TestCaptureHeader header {};
|
||||||
@@ -104,12 +110,13 @@ std::filesystem::path makeTempDirectory()
|
|||||||
|
|
||||||
int runClient(const FormatCase & format, const char * damage,
|
int runClient(const FormatCase & format, const char * damage,
|
||||||
const std::filesystem::path & capture,
|
const std::filesystem::path & capture,
|
||||||
const std::filesystem::path & log)
|
const std::filesystem::path & log, unsigned stride)
|
||||||
{
|
{
|
||||||
const std::string size = std::to_string(kWidth) + "x" +
|
const std::string size = std::to_string(kWidth) + "x" +
|
||||||
std::to_string(kHeight);
|
std::to_string(kHeight);
|
||||||
const std::string width = "test:width=" + std::to_string(kWidth);
|
const std::string width = "test:width=" + std::to_string(kWidth);
|
||||||
const std::string height = "test:height=" + std::to_string(kHeight);
|
const std::string height = "test:height=" + std::to_string(kHeight);
|
||||||
|
const std::string strideArg = "test:stride=" + std::to_string(stride);
|
||||||
const std::string formatArg = std::string("test:format=") + format.name;
|
const std::string formatArg = std::string("test:format=") + format.name;
|
||||||
const std::string damageArg = std::string("test:damage=") + damage;
|
const std::string damageArg = std::string("test:damage=") + damage;
|
||||||
const std::string count = "test:frameCount=" +
|
const std::string count = "test:frameCount=" +
|
||||||
@@ -124,6 +131,7 @@ int runClient(const FormatCase & format, const char * damage,
|
|||||||
"app:renderer=EGL",
|
"app:renderer=EGL",
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
|
strideArg,
|
||||||
formatArg,
|
formatArg,
|
||||||
damageArg,
|
damageArg,
|
||||||
"test:frameRate=60",
|
"test:frameRate=60",
|
||||||
@@ -187,18 +195,21 @@ int runClient(const FormatCase & format, const char * damage,
|
|||||||
return 124;
|
return 124;
|
||||||
}
|
}
|
||||||
|
|
||||||
Capture produceCapture(const FormatCase & format, const char * damage)
|
Capture produceCapture(const FormatCase & format, const char * damage,
|
||||||
|
unsigned stride = 0)
|
||||||
{
|
{
|
||||||
Capture result;
|
Capture result;
|
||||||
result.directory = makeTempDirectory();
|
result.directory = makeTempDirectory();
|
||||||
if (result.directory.empty())
|
if (result.directory.empty())
|
||||||
return result;
|
return result;
|
||||||
result.path = result.directory /
|
std::string artifactName = std::string(format.name) + "-" + damage;
|
||||||
(std::string(format.name) + "-" + damage + ".lgcapture");
|
if (stride)
|
||||||
result.log = result.directory /
|
artifactName += "-stride" + std::to_string(stride);
|
||||||
(std::string(format.name) + "-" + damage + ".log");
|
result.path = result.directory / (artifactName + ".lgcapture");
|
||||||
|
result.log = result.directory / (artifactName + ".log");
|
||||||
|
|
||||||
const int status = runClient(format, damage, result.path, result.log);
|
const int status =
|
||||||
|
runClient(format, damage, result.path, result.log, stride);
|
||||||
EXPECT_EQ(status, 0) << readText(result.log);
|
EXPECT_EQ(status, 0) << readText(result.log);
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
return result;
|
return result;
|
||||||
@@ -562,4 +573,52 @@ INSTANTIATE_TEST_SUITE_P(FormatDamageMatrix, RenderPipelineTest,
|
|||||||
),
|
),
|
||||||
renderCaseName);
|
renderCaseName);
|
||||||
|
|
||||||
|
using StrideRenderCase = std::tuple<StrideCase, DamageCase>;
|
||||||
|
|
||||||
|
class StrideRenderPipelineTest :
|
||||||
|
public testing::TestWithParam<StrideRenderCase>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_P(StrideRenderPipelineTest, MatchesReference)
|
||||||
|
{
|
||||||
|
const StrideCase & stride = std::get<0>(GetParam());
|
||||||
|
const DamageCase & damage = std::get<1>(GetParam());
|
||||||
|
const FormatCase format = {
|
||||||
|
"bgra", FRAME_TYPE_BGRA, false, false
|
||||||
|
};
|
||||||
|
Capture capture = produceCapture(format, damage.name, stride.stride);
|
||||||
|
ASSERT_FALSE(capture.data.empty()) << "artifacts: " << capture.directory;
|
||||||
|
|
||||||
|
const std::string clientLog = readText(capture.log);
|
||||||
|
const std::string expectedLayout =
|
||||||
|
"stride:" + std::to_string(stride.stride) +
|
||||||
|
" pitch:" + std::to_string(stride.stride * 4);
|
||||||
|
EXPECT_NE(clientLog.find(expectedLayout), std::string::npos) << clientLog;
|
||||||
|
|
||||||
|
compareReference(format, capture);
|
||||||
|
if (!testing::Test::HasFailure())
|
||||||
|
std::filesystem::remove_all(capture.directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string strideRenderCaseName(
|
||||||
|
const testing::TestParamInfo<StrideRenderCase> & info)
|
||||||
|
{
|
||||||
|
return std::string(std::get<0>(info.param).name) + "_" +
|
||||||
|
std::get<1>(info.param).name;
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(BGRAPaddedStride, StrideRenderPipelineTest,
|
||||||
|
testing::Combine(
|
||||||
|
testing::Values(
|
||||||
|
StrideCase {"stride128", 128},
|
||||||
|
StrideCase {"stride1280", 1280}
|
||||||
|
),
|
||||||
|
testing::Values(
|
||||||
|
DamageCase {"full"},
|
||||||
|
DamageCase {"moving"}
|
||||||
|
)
|
||||||
|
),
|
||||||
|
strideRenderCaseName);
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ struct LG_Transport
|
|||||||
{
|
{
|
||||||
unsigned width;
|
unsigned width;
|
||||||
unsigned height;
|
unsigned height;
|
||||||
|
unsigned stride;
|
||||||
unsigned frameRate;
|
unsigned frameRate;
|
||||||
unsigned frameCount;
|
unsigned frameCount;
|
||||||
bool realtime;
|
bool realtime;
|
||||||
@@ -110,6 +111,14 @@ static void test_setup(void)
|
|||||||
.type = OPTION_TYPE_INT,
|
.type = OPTION_TYPE_INT,
|
||||||
.value.x_int = 1080,
|
.value.x_int = 1080,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.module = "test",
|
||||||
|
.name = "stride",
|
||||||
|
.description =
|
||||||
|
"Generated frame stride in storage elements, or zero for packed",
|
||||||
|
.type = OPTION_TYPE_INT,
|
||||||
|
.value.x_int = 0,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.module = "test",
|
.module = "test",
|
||||||
.name = "frameRate",
|
.name = "frameRate",
|
||||||
@@ -276,13 +285,18 @@ static bool test_setFormat(struct LG_Transport * this, unsigned index)
|
|||||||
if (this->format.version && this->formatIndex == index)
|
if (this->format.version && this->formatIndex == index)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const struct TestFormat * testFormat = &testFormats[index];
|
const struct TestFormat * testFormat = &testFormats[index];
|
||||||
const uint32_t version = this->format.version + 1;
|
const uint32_t version = this->format.version + 1;
|
||||||
const bool packedBGR =
|
const bool packedBGR =
|
||||||
testFormat->type == FRAME_TYPE_BGR_32;
|
testFormat->type == FRAME_TYPE_BGR_32;
|
||||||
const unsigned pitch = packedBGR ?
|
const unsigned packedPitch = packedBGR ?
|
||||||
ALIGN_PAD(this->width * 3, 4) :
|
ALIGN_PAD(this->width * 3, 4) :
|
||||||
this->width * testFormat->bytesPerPixel;
|
this->width * testFormat->bytesPerPixel;
|
||||||
|
const unsigned stride = this->stride ? this->stride :
|
||||||
|
packedBGR ? packedPitch / 4 : this->width;
|
||||||
|
const unsigned pitch = this->stride ?
|
||||||
|
stride * testFormat->bytesPerPixel :
|
||||||
|
packedPitch;
|
||||||
|
|
||||||
this->formatIndex = index;
|
this->formatIndex = index;
|
||||||
this->format = (LG_TransportFrameFormat) {
|
this->format = (LG_TransportFrameFormat) {
|
||||||
@@ -295,7 +309,7 @@ static bool test_setFormat(struct LG_Transport * this, unsigned index)
|
|||||||
.frameWidth = this->width,
|
.frameWidth = this->width,
|
||||||
.frameHeight = this->height,
|
.frameHeight = this->height,
|
||||||
.rotation = FRAME_ROT_0,
|
.rotation = FRAME_ROT_0,
|
||||||
.stride = packedBGR ? pitch / 4 : this->width,
|
.stride = stride,
|
||||||
.pitch = pitch,
|
.pitch = pitch,
|
||||||
.hdr = testFormat->hdr,
|
.hdr = testFormat->hdr,
|
||||||
.hdrPQ = testFormat->hdrPQ,
|
.hdrPQ = testFormat->hdrPQ,
|
||||||
@@ -317,6 +331,7 @@ static bool test_create(LG_Transport ** result)
|
|||||||
|
|
||||||
const int width = option_get_int("test", "width");
|
const int width = option_get_int("test", "width");
|
||||||
const int height = option_get_int("test", "height");
|
const int height = option_get_int("test", "height");
|
||||||
|
const int stride = option_get_int("test", "stride");
|
||||||
const int frameRate = option_get_int("test", "frameRate");
|
const int frameRate = option_get_int("test", "frameRate");
|
||||||
const int frameCount = option_get_int("test", "frameCount");
|
const int frameCount = option_get_int("test", "frameCount");
|
||||||
const char * format = option_get_string("test", "format");
|
const char * format = option_get_string("test", "format");
|
||||||
@@ -324,12 +339,15 @@ static bool test_create(LG_Transport ** result)
|
|||||||
const int damageMode = damage ? test_findDamageMode(damage) : -1;
|
const int damageMode = damage ? test_findDamageMode(damage) : -1;
|
||||||
const bool cycleFormats = strcmp(format, "cycle") == 0;
|
const bool cycleFormats = strcmp(format, "cycle") == 0;
|
||||||
const int formatIndex = cycleFormats ? 0 : test_findFormat(format);
|
const int formatIndex = cycleFormats ? 0 : test_findFormat(format);
|
||||||
const unsigned maxBytesPerPixel = formatIndex < 0 ? 0 :
|
const unsigned maxBytesPerPixel = formatIndex < 0 ? 0 :
|
||||||
cycleFormats ? 8 : testFormats[formatIndex].bytesPerPixel;
|
cycleFormats ? 8 : testFormats[formatIndex].bytesPerPixel;
|
||||||
|
const size_t bufferStride = stride > 0 ? (size_t)stride :
|
||||||
|
width > 0 ? (size_t)width : 0;
|
||||||
if (width < 1 || height < 1 || !maxBytesPerPixel || damageMode < 0 ||
|
if (width < 1 || height < 1 || !maxBytesPerPixel || damageMode < 0 ||
|
||||||
width > (int)(UINT32_MAX / maxBytesPerPixel) ||
|
stride < 0 || (stride && stride < width) ||
|
||||||
|
bufferStride > UINT32_MAX / maxBytesPerPixel ||
|
||||||
frameRate < 1 || frameRate > 1000000000 || frameCount < 0 ||
|
frameRate < 1 || frameRate > 1000000000 || frameCount < 0 ||
|
||||||
(size_t)width > (SIZE_MAX - sizeof(FrameBuffer)) /
|
bufferStride > (SIZE_MAX - sizeof(FrameBuffer)) /
|
||||||
maxBytesPerPixel / (size_t)height)
|
maxBytesPerPixel / (size_t)height)
|
||||||
{
|
{
|
||||||
DEBUG_ERROR(
|
DEBUG_ERROR(
|
||||||
@@ -340,6 +358,7 @@ static bool test_create(LG_Transport ** result)
|
|||||||
|
|
||||||
this->width = width;
|
this->width = width;
|
||||||
this->height = height;
|
this->height = height;
|
||||||
|
this->stride = stride;
|
||||||
this->frameRate = frameRate;
|
this->frameRate = frameRate;
|
||||||
this->frameCount = frameCount;
|
this->frameCount = frameCount;
|
||||||
this->realtime = option_get_bool("test", "realtime");
|
this->realtime = option_get_bool("test", "realtime");
|
||||||
@@ -350,7 +369,7 @@ static bool test_create(LG_Transport ** result)
|
|||||||
test_initPQLUT(this);
|
test_initPQLUT(this);
|
||||||
|
|
||||||
const size_t dataSize =
|
const size_t dataSize =
|
||||||
(size_t)this->width * this->height * maxBytesPerPixel;
|
bufferStride * this->height * maxBytesPerPixel;
|
||||||
for (unsigned i = 0; i < TEST_BUFFER_COUNT; ++i)
|
for (unsigned i = 0; i < TEST_BUFFER_COUNT; ++i)
|
||||||
{
|
{
|
||||||
this->buffers[i].framebuffer = malloc(sizeof(FrameBuffer) + dataSize);
|
this->buffers[i].framebuffer = malloc(sizeof(FrameBuffer) + dataSize);
|
||||||
@@ -481,25 +500,29 @@ static void test_getColor(const struct LG_Transport * this,
|
|||||||
static void test_generateFrame(struct LG_Transport * this, FrameBuffer * fb)
|
static void test_generateFrame(struct LG_Transport * this, FrameBuffer * fb)
|
||||||
{
|
{
|
||||||
uint8_t * data = framebuffer_get_data(fb);
|
uint8_t * data = framebuffer_get_data(fb);
|
||||||
if (this->format.type == FRAME_TYPE_BGR_32)
|
if (this->stride)
|
||||||
|
memset(data, 0xa5 ^ (uint8_t)this->serial,
|
||||||
|
(size_t)this->format.pitch * this->height);
|
||||||
|
else if (this->format.type == FRAME_TYPE_BGR_32)
|
||||||
memset(data, 0, (size_t)this->format.pitch * this->height);
|
memset(data, 0, (size_t)this->format.pitch * this->height);
|
||||||
|
|
||||||
for (unsigned y = 0; y < this->height; ++y)
|
for (unsigned y = 0; y < this->height; ++y)
|
||||||
|
{
|
||||||
|
uint8_t * row = data + (size_t)y * this->format.pitch;
|
||||||
for (unsigned x = 0; x < this->width; ++x)
|
for (unsigned x = 0; x < this->width; ++x)
|
||||||
{
|
{
|
||||||
uint8_t r, g, b;
|
uint8_t r, g, b;
|
||||||
test_getColor(this, x, y, &r, &g, &b);
|
test_getColor(this, x, y, &r, &g, &b);
|
||||||
const size_t pixel = (size_t)y * this->width + x;
|
|
||||||
switch (this->format.type)
|
switch (this->format.type)
|
||||||
{
|
{
|
||||||
case FRAME_TYPE_BGRA:
|
case FRAME_TYPE_BGRA:
|
||||||
((uint32_t *)data)[pixel] =
|
((uint32_t *)row)[x] =
|
||||||
0xff000000U | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
|
0xff000000U | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FRAME_TYPE_BGR_32:
|
case FRAME_TYPE_BGR_32:
|
||||||
{
|
{
|
||||||
uint8_t * bgr = data + (size_t)y * this->format.pitch + x * 3;
|
uint8_t * bgr = row + x * 3;
|
||||||
bgr[0] = b;
|
bgr[0] = b;
|
||||||
bgr[1] = g;
|
bgr[1] = g;
|
||||||
bgr[2] = r;
|
bgr[2] = r;
|
||||||
@@ -507,14 +530,14 @@ static void test_generateFrame(struct LG_Transport * this, FrameBuffer * fb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
case FRAME_TYPE_RGBA:
|
case FRAME_TYPE_RGBA:
|
||||||
((uint32_t *)data)[pixel] =
|
((uint32_t *)row)[x] =
|
||||||
0xff000000U | ((uint32_t)b << 16) | ((uint32_t)g << 8) | r;
|
0xff000000U | ((uint32_t)b << 16) | ((uint32_t)g << 8) | r;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FRAME_TYPE_RGB_24:
|
case FRAME_TYPE_RGB_24:
|
||||||
data[pixel * 3 ] = r;
|
row[x * 3 ] = r;
|
||||||
data[pixel * 3 + 1] = g;
|
row[x * 3 + 1] = g;
|
||||||
data[pixel * 3 + 2] = b;
|
row[x * 3 + 2] = b;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FRAME_TYPE_RGBA10:
|
case FRAME_TYPE_RGBA10:
|
||||||
@@ -528,7 +551,7 @@ static void test_generateFrame(struct LG_Transport * this, FrameBuffer * fb)
|
|||||||
r709 * 0.0690973f + g709 * 0.9195404f + b709 * 0.0113623f;
|
r709 * 0.0690973f + g709 * 0.9195404f + b709 * 0.0113623f;
|
||||||
const float b2020 =
|
const float b2020 =
|
||||||
r709 * 0.0163914f + g709 * 0.0880133f + b709 * 0.8955953f;
|
r709 * 0.0163914f + g709 * 0.0880133f + b709 * 0.8955953f;
|
||||||
((uint32_t *)data)[pixel] =
|
((uint32_t *)row)[x] =
|
||||||
((uint32_t)test_scRGBToPQ(this, r2020) ) |
|
((uint32_t)test_scRGBToPQ(this, r2020) ) |
|
||||||
((uint32_t)test_scRGBToPQ(this, g2020) << 10) |
|
((uint32_t)test_scRGBToPQ(this, g2020) << 10) |
|
||||||
((uint32_t)test_scRGBToPQ(this, b2020) << 20) |
|
((uint32_t)test_scRGBToPQ(this, b2020) << 20) |
|
||||||
@@ -538,7 +561,7 @@ static void test_generateFrame(struct LG_Transport * this, FrameBuffer * fb)
|
|||||||
|
|
||||||
case FRAME_TYPE_RGBA16F:
|
case FRAME_TYPE_RGBA16F:
|
||||||
{
|
{
|
||||||
uint16_t * rgba = (uint16_t *)data + pixel * 4;
|
uint16_t * rgba = (uint16_t *)row + x * 4;
|
||||||
rgba[0] = test_floatToHalf((float)r * 4.0f / 255.0f);
|
rgba[0] = test_floatToHalf((float)r * 4.0f / 255.0f);
|
||||||
rgba[1] = test_floatToHalf((float)g * 4.0f / 255.0f);
|
rgba[1] = test_floatToHalf((float)g * 4.0f / 255.0f);
|
||||||
rgba[2] = test_floatToHalf((float)b * 4.0f / 255.0f);
|
rgba[2] = test_floatToHalf((float)b * 4.0f / 255.0f);
|
||||||
@@ -550,6 +573,7 @@ static void test_generateFrame(struct LG_Transport * this, FrameBuffer * fb)
|
|||||||
DEBUG_UNREACHABLE();
|
DEBUG_UNREACHABLE();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
framebuffer_set_write_ptr(fb, (size_t)this->format.pitch * this->height);
|
framebuffer_set_write_ptr(fb, (size_t)this->format.pitch * this->height);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user