blob: 545e59ef0c1de7d3c566749a2fbe923e1f2c1ce3 [file] [log] [blame]
/*
* Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <vndk/hardware_buffer.h>
#include "EventGenerator.h"
#include "InputFrame.h"
#include "MockEngine.h"
#include "OutputConfig.pb.h"
#include "PixelFormatUtils.h"
#include "PixelStreamManager.h"
#include "RunnerComponent.h"
#include "StreamEngineInterface.h"
#include "StreamManager.h"
#include "gmock/gmock-matchers.h"
#include "types/Status.h"
using ::android::automotive::computepipe::runner::RunnerComponentInterface;
using ::android::automotive::computepipe::runner::RunnerEvent;
using ::android::automotive::computepipe::runner::generator::DefaultEvent;
using ::testing::Contains;
using ::testing::Not;
using ::testing::Return;
namespace android {
namespace automotive {
namespace computepipe {
namespace runner {
namespace stream_manager {
namespace {
MATCHER_P(ContainsDataFromFrame, data, "") {
const uint8_t* dataPtr = data->getFramePtr();
FrameInfo info = data->getFrameInfo();
AHardwareBuffer_Desc desc;
AHardwareBuffer_describe(arg, &desc);
if (desc.width != info.width) {
*result_listener << "Width does not match with values " << desc.width << " and "
<< info.width;
return false;
}
if (desc.height != info.height) {
*result_listener << "Height does not match with values " << desc.height << " and "
<< info.height;
return false;
}
AHardwareBuffer_Format expectedFormat = PixelFormatToHardwareBufferFormat(info.format);
if (expectedFormat != desc.format) {
*result_listener << "Format does not match";
return false;
}
void* mappedBuffer = nullptr;
int err = AHardwareBuffer_lock(arg, AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, -1, nullptr,
&mappedBuffer);
if (err != 0 || mappedBuffer == nullptr) {
*result_listener << "Unable to lock the buffer for reading and comparing";
return false;
}
bool dataMatched = true;
int bytesPerPixel = numBytesPerPixel(expectedFormat);
for (int y = 0; y < info.height; y++) {
uint8_t* mappedRow = (uint8_t*)mappedBuffer + y * desc.stride * bytesPerPixel;
if (memcmp(mappedRow, dataPtr + y * info.stride,
std::min(info.stride, desc.stride * bytesPerPixel))) {
*result_listener << "Row " << y << " does not match";
dataMatched = false;
break;
}
}
AHardwareBuffer_unlock(arg, nullptr);
return dataMatched;
}
TEST(PixelMemHandleTest, SuccessfullyCreatesMemHandleOnFirstAttempt) {
int bufferId = 10;
int streamId = 1;
uint64_t timestamp = 100;
PixelMemHandle memHandle(bufferId, streamId, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN);
EXPECT_EQ(memHandle.getBufferId(), bufferId);
EXPECT_EQ(memHandle.getStreamId(), streamId);
EXPECT_EQ(memHandle.getHardwareBuffer(), nullptr);
std::vector<uint8_t> data(16 * 16 * 3, 0);
InputFrame frame(16, 16, PixelFormat::RGB, 16 * 3, &data[0]);
Status status = memHandle.setFrameData(timestamp, frame);
EXPECT_EQ(status, Status::SUCCESS);
ASSERT_NE(memHandle.getHardwareBuffer(), nullptr);
AHardwareBuffer_Desc desc;
AHardwareBuffer* buffer = memHandle.getHardwareBuffer();
AHardwareBuffer_describe(buffer, &desc);
EXPECT_EQ(desc.height, 16);
EXPECT_EQ(desc.width, 16);
EXPECT_EQ(desc.usage,
AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN);
EXPECT_EQ(desc.format, AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM);
EXPECT_THAT(buffer, ContainsDataFromFrame(&frame));
}
TEST(PixelMemHandleTest, FailsToOverwriteFrameDataWithDifferentImageFormat) {
int bufferId = 10;
int streamId = 1;
uint64_t timestamp = 100;
PixelMemHandle memHandle(bufferId, streamId, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN);
EXPECT_EQ(memHandle.getBufferId(), bufferId);
EXPECT_EQ(memHandle.getStreamId(), streamId);
EXPECT_EQ(memHandle.getHardwareBuffer(), nullptr);
uint8_t data[16 * 16 * 3] = {0};
InputFrame frame(16, 16, PixelFormat::RGB, 16 * 3, &data[0]);
Status status = memHandle.setFrameData(timestamp, frame);
EXPECT_EQ(status, Status::SUCCESS);
ASSERT_NE(memHandle.getHardwareBuffer(), nullptr);
InputFrame frameWithNewFormat(16, 16, PixelFormat::RGBA, 16 * 4, nullptr);
status = memHandle.setFrameData(timestamp, frameWithNewFormat);
EXPECT_EQ(status, Status::INVALID_ARGUMENT);
InputFrame frameWithNewDimensions(8, 8, PixelFormat::RGB, 8 * 3, nullptr);
status = memHandle.setFrameData(timestamp, frameWithNewDimensions);
EXPECT_EQ(status, Status::INVALID_ARGUMENT);
}
TEST(PixelMemHandleTest, SuccessfullyOverwritesOldData) {
int bufferId = 10;
int streamId = 1;
uint64_t timestamp = 100;
PixelMemHandle memHandle(bufferId, streamId, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN);
EXPECT_EQ(memHandle.getBufferId(), bufferId);
EXPECT_EQ(memHandle.getStreamId(), streamId);
EXPECT_EQ(memHandle.getHardwareBuffer(), nullptr);
std::vector<uint8_t> data(16 * 16 * 3, 0);
InputFrame frame(16, 16, PixelFormat::RGB, 16 * 3, &data[0]);
Status status = memHandle.setFrameData(timestamp, frame);
EXPECT_EQ(status, Status::SUCCESS);
ASSERT_NE(memHandle.getHardwareBuffer(), nullptr);
EXPECT_THAT(memHandle.getHardwareBuffer(), ContainsDataFromFrame(&frame));
std::vector<uint8_t> newData(16 * 16 * 3, 1);
uint64_t newTimestamp = 200;
InputFrame newFrame(16, 16, PixelFormat::RGB, 16 * 3, &newData[0]);
memHandle.setFrameData(newTimestamp, newFrame);
EXPECT_THAT(memHandle.getHardwareBuffer(), ContainsDataFromFrame(&newFrame));
EXPECT_THAT(memHandle.getTimeStamp(), newTimestamp);
}
TEST(PixelMemHandleTest, CreatesBuffersOfExpectedFormats) {
int bufferId = 10;
int streamId = 1;
uint64_t timestamp = 100;
std::vector<uint8_t> rgbData(16 * 16 * 3, 10);
InputFrame rgbFrame(16, 16, PixelFormat::RGB, 16 * 3, &rgbData[0]);
PixelMemHandle rgbHandle(bufferId, streamId, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN);
rgbHandle.setFrameData(timestamp, rgbFrame);
EXPECT_THAT(rgbHandle.getHardwareBuffer(), ContainsDataFromFrame(&rgbFrame));
std::vector<uint8_t> rgbaData(16 * 16 * 4, 20);
InputFrame rgbaFrame(16, 16, PixelFormat::RGBA, 16 * 4, &rgbaData[0]);
PixelMemHandle rgbaHandle(bufferId, streamId, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN);
rgbaHandle.setFrameData(timestamp, rgbaFrame);
EXPECT_THAT(rgbaHandle.getHardwareBuffer(), ContainsDataFromFrame(&rgbaFrame));
std::vector<uint8_t> yData(16 * 16, 40);
InputFrame yFrame(16, 16, PixelFormat::GRAY, 16, &yData[0]);
PixelMemHandle yHandle(bufferId, streamId, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN);
yHandle.setFrameData(timestamp, yFrame);
EXPECT_THAT(yHandle.getHardwareBuffer(), ContainsDataFromFrame(&yFrame));
}
std::pair<std::shared_ptr<MockEngine>, std::unique_ptr<StreamManager>> CreateStreamManagerAndEngine(
int maxInFlightPackets) {
StreamManagerFactory factory;
proto::OutputConfig outputConfig;
outputConfig.set_type(proto::PacketType::PIXEL_DATA);
outputConfig.set_stream_name("pixel_stream");
std::shared_ptr<MockEngine> mockEngine = std::make_shared<MockEngine>();
std::unique_ptr<StreamManager> manager =
factory.getStreamManager(outputConfig, mockEngine, maxInFlightPackets);
return std::pair(mockEngine, std::move(manager));
}
TEST(PixelStreamManagerTest, PacketQueueingProducesACallback) {
// Create stream manager
int maxInFlightPackets = 1;
auto [mockEngine, manager] = CreateStreamManagerAndEngine(maxInFlightPackets);
DefaultEvent e = DefaultEvent::generateEntryEvent(DefaultEvent::Phase::RUN);
ASSERT_EQ(manager->handleExecutionPhase(e), Status::SUCCESS);
std::vector<uint8_t> data(16 * 16 * 3, 100);
InputFrame frame(16, 16, PixelFormat::RGB, 16 * 3, &data[0]);
std::shared_ptr<MemHandle> memHandle;
EXPECT_CALL((*mockEngine), dispatchPacket)
.WillOnce(testing::DoAll(testing::SaveArg<0>(&memHandle), (Return(Status::SUCCESS))));
EXPECT_EQ(manager->queuePacket(frame, 0), Status::SUCCESS);
sleep(1);
ASSERT_NE(memHandle, nullptr);
EXPECT_THAT(memHandle->getHardwareBuffer(), ContainsDataFromFrame(&frame));
EXPECT_THAT(memHandle->getTimeStamp(), 0);
EXPECT_THAT(memHandle->getStreamId(), 0);
}
TEST(PixelStreamManagerTest, MorePacketsThanMaxInFlightAreNotDispatched) {
int maxInFlightPackets = 3;
auto [mockEngine, manager] = CreateStreamManagerAndEngine(maxInFlightPackets);
DefaultEvent e = DefaultEvent::generateEntryEvent(DefaultEvent::Phase::RUN);
ASSERT_EQ(manager->handleExecutionPhase(e), Status::SUCCESS);
std::vector<uint8_t> data(16 * 16 * 3, 100);
InputFrame frame(16, 16, PixelFormat::RGB, 16 * 3, &data[0]);
std::set<int> activeBufferIds;
std::shared_ptr<MemHandle> memHandle;
EXPECT_CALL((*mockEngine), dispatchPacket)
.Times(3)
.WillRepeatedly(testing::DoAll(testing::SaveArg<0>(&memHandle), (Return(Status::SUCCESS))));
EXPECT_EQ(manager->queuePacket(frame, 0), Status::SUCCESS);
sleep(1);
ASSERT_NE(memHandle, nullptr);
EXPECT_THAT(memHandle->getHardwareBuffer(), ContainsDataFromFrame(&frame));
EXPECT_THAT(memHandle->getTimeStamp(), 0);
EXPECT_THAT(memHandle->getStreamId(), 0);
activeBufferIds.insert(memHandle->getBufferId());
EXPECT_EQ(manager->queuePacket(frame, 10), Status::SUCCESS);
sleep(1);
ASSERT_NE(memHandle, nullptr);
EXPECT_THAT(memHandle->getHardwareBuffer(), ContainsDataFromFrame(&frame));
EXPECT_THAT(memHandle->getTimeStamp(), 10);
EXPECT_THAT(memHandle->getStreamId(), 0);
EXPECT_THAT(activeBufferIds, Not(Contains(memHandle->getBufferId())));
activeBufferIds.insert(memHandle->getBufferId());
EXPECT_EQ(manager->queuePacket(frame, 20), Status::SUCCESS);
sleep(1);
ASSERT_NE(memHandle, nullptr);
EXPECT_THAT(memHandle->getHardwareBuffer(), ContainsDataFromFrame(&frame));
EXPECT_THAT(memHandle->getTimeStamp(), 20);
EXPECT_THAT(memHandle->getStreamId(), 0);
EXPECT_THAT(activeBufferIds, Not(Contains(memHandle->getBufferId())));
activeBufferIds.insert(memHandle->getBufferId());
// No new packet is produced as we have now reached the limit of number of
// packets.
EXPECT_EQ(manager->queuePacket(frame, 30), Status::SUCCESS);
sleep(1);
EXPECT_THAT(memHandle->getTimeStamp(), 20);
EXPECT_THAT(activeBufferIds, Contains(memHandle->getBufferId()));
}
TEST(PixelStreamManagerTest, DoneWithPacketCallReleasesAPacket) {
int maxInFlightPackets = 1;
auto [mockEngine, manager] = CreateStreamManagerAndEngine(maxInFlightPackets);
std::set<int> activeBufferIds;
DefaultEvent e = DefaultEvent::generateEntryEvent(DefaultEvent::Phase::RUN);
ASSERT_EQ(manager->handleExecutionPhase(e), Status::SUCCESS);
std::vector<uint8_t> data(16 * 16 * 3, 100);
InputFrame frame(16, 16, PixelFormat::RGB, 16 * 3, &data[0]);
std::shared_ptr<MemHandle> memHandle;
EXPECT_CALL((*mockEngine), dispatchPacket)
.Times(2)
.WillRepeatedly(testing::DoAll(testing::SaveArg<0>(&memHandle), (Return(Status::SUCCESS))));
EXPECT_EQ(manager->queuePacket(frame, 10), Status::SUCCESS);
sleep(1);
ASSERT_NE(memHandle, nullptr);
activeBufferIds.insert(memHandle->getBufferId());
EXPECT_THAT(memHandle->getHardwareBuffer(), ContainsDataFromFrame(&frame));
EXPECT_THAT(memHandle->getTimeStamp(), 10);
EXPECT_THAT(memHandle->getStreamId(), 0);
// Check that new packet has not been dispatched as the old packet has not been released yet.
EXPECT_EQ(manager->queuePacket(frame, 20), Status::SUCCESS);
sleep(1);
ASSERT_NE(memHandle, nullptr);
EXPECT_THAT(memHandle->getTimeStamp(), 10);
EXPECT_THAT(manager->freePacket(memHandle->getBufferId()), Status::SUCCESS);
EXPECT_EQ(manager->queuePacket(frame, 30), Status::SUCCESS);
sleep(1);
ASSERT_NE(memHandle, nullptr);
EXPECT_THAT(memHandle->getTimeStamp(), 30);
}
TEST(PixelStreamManagerTest, EngineReceivesEndOfStreamCallbackOnStoppage) {
int maxInFlightPackets = 1;
auto [mockEngine, manager] = CreateStreamManagerAndEngine(maxInFlightPackets);
DefaultEvent e = DefaultEvent::generateEntryEvent(DefaultEvent::Phase::RUN);
ASSERT_EQ(manager->handleExecutionPhase(e), Status::SUCCESS);
std::vector<uint8_t> data(16 * 16 * 3, 100);
InputFrame frame(16, 16, PixelFormat::RGB, 16 * 3, &data[0]);
std::shared_ptr<MemHandle> memHandle;
EXPECT_CALL((*mockEngine), dispatchPacket)
.WillOnce(testing::DoAll(testing::SaveArg<0>(&memHandle), (Return(Status::SUCCESS))));
EXPECT_EQ(manager->queuePacket(frame, 10), Status::SUCCESS);
sleep(1);
ASSERT_NE(memHandle, nullptr);
EXPECT_THAT(memHandle->getHardwareBuffer(), ContainsDataFromFrame(&frame));
EXPECT_THAT(memHandle->getTimeStamp(), 10);
EXPECT_THAT(memHandle->getStreamId(), 0);
EXPECT_EQ(manager->handleStopImmediatePhase(e), Status::SUCCESS);
}
} // namespace
} // namespace stream_manager
} // namespace runner
} // namespace computepipe
} // namespace automotive
} // namespace android