blob: 1294a4eca9d98278fea73ab76ed075aa9ab51dbd [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <lib/fake_ddk/fake_ddk.h>
#include <lib/sys/cpp/component_context.h>
#include "src/camera/drivers/controller/memory_allocation.h"
#include "src/camera/drivers/controller/pipeline_manager.h"
#include "src/camera/drivers/controller/sherlock/common_util.h"
#include "src/camera/drivers/controller/sherlock/monitoring_config.h"
#include "src/camera/drivers/controller/sherlock/video_conferencing_config.h"
#include "src/camera/drivers/controller/test/fake_sysmem.h"
#include "src/camera/lib/format_conversion/format_conversion.h"
#include "src/lib/testing/loop_fixture/test_loop_fixture.h"
// Relaxes memory placement constraints to be more permissive. This improves the reliability of
// allocation as it is no longer competing with other components in the system for fixed
// allocations of e.g. contiguous memory.
void RelaxMemoryConstraints(
std::vector<fuchsia::sysmem::BufferCollectionConstraints>& constraints) {
for (auto& c : constraints) {
c.buffer_memory_constraints.cpu_domain_supported = true;
c.buffer_memory_constraints.ram_domain_supported = true;
c.buffer_memory_constraints.inaccessible_domain_supported = true;
c.buffer_memory_constraints.secure_required = false;
c.buffer_memory_constraints.physically_contiguous_required = false;
}
}
// NOTE: In this test, we are actually just unit testing
// the sysmem allocation using different constraints.
namespace camera {
class ControllerMemoryAllocatorTest : public gtest::TestLoopFixture {
public:
ControllerMemoryAllocatorTest()
: context_(sys::ComponentContext::CreateAndServeOutgoingDirectory()),
fake_sysmem_([this](auto request) { return context_->svc()->Connect(std::move(request)); }),
sysmem_(fake_sysmem_.client()) {}
void SetUp() override {
ASSERT_EQ(ZX_OK, context_->svc()->Connect(sysmem_allocator_.NewRequest()));
ASSERT_EQ(ZX_OK, zx::event::create(0, &event_));
controller_memory_allocator_ = std::make_unique<ControllerMemoryAllocator>(sysmem_);
pipeline_manager_ = std::make_unique<PipelineManager>(
dispatcher(), sysmem_, isp_, gdc_, ge2d_,
fit::bind_member(this, &ControllerMemoryAllocatorTest::LoadFirmware));
}
void TearDown() override {
context_ = nullptr;
sysmem_allocator_ = nullptr;
}
fpromise::result<std::pair<zx::vmo, size_t>, zx_status_t> LoadFirmware(const std::string& path) {
constexpr size_t kVmoSize = 4096;
zx::vmo vmo;
zx_status_t status = zx::vmo::create(kVmoSize, 0, &vmo);
if (status != ZX_OK) {
return fpromise::error(status);
}
return fpromise::ok(std::pair{std::move(vmo), kVmoSize});
}
zx::event event_;
std::unique_ptr<sys::ComponentContext> context_;
fuchsia::sysmem::AllocatorSyncPtr sysmem_allocator_;
std::unique_ptr<ControllerMemoryAllocator> controller_memory_allocator_;
std::unique_ptr<camera::PipelineManager> pipeline_manager_;
FakeSysmem fake_sysmem_;
ddk::SysmemProtocolClient sysmem_;
ddk::IspProtocolClient isp_;
ddk::GdcProtocolClient gdc_;
ddk::Ge2dProtocolClient ge2d_;
};
// Validate FR --> GDC1 --> OutputStreamMLDS
// Buffer collection constraints.
TEST_F(ControllerMemoryAllocatorTest, MonitorConfigFR) {
auto internal_config = MonitorConfigFullRes();
auto fr_constraints = *internal_config.output_constraints;
auto gdc1_constraints = *internal_config.child_nodes[0].child_nodes[1].input_constraints;
BufferCollection buffer_collection;
std::vector<fuchsia::sysmem::BufferCollectionConstraints> constraints;
constraints.push_back(fr_constraints);
constraints.push_back(gdc1_constraints);
RelaxMemoryConstraints(constraints);
ASSERT_EQ(ZX_OK, controller_memory_allocator_->AllocateSharedMemory(
constraints, buffer_collection, "TestMonitorConfigFR"));
EXPECT_GT(buffer_collection.buffers.settings.buffer_settings.size_bytes,
kOutputStreamMlFRHeight * kOutputStreamMlFRWidth);
EXPECT_TRUE(buffer_collection.buffers.settings.has_image_format_constraints);
EXPECT_EQ(fuchsia::sysmem::PixelFormatType::NV12,
buffer_collection.buffers.settings.image_format_constraints.pixel_format.type);
EXPECT_EQ(kOutputStreamMlFRHeight,
buffer_collection.buffers.settings.image_format_constraints.required_max_coded_height);
EXPECT_EQ(kOutputStreamMlFRWidth,
buffer_collection.buffers.settings.image_format_constraints.required_max_coded_width);
EXPECT_EQ(kIspBytesPerRowDivisor,
buffer_collection.buffers.settings.image_format_constraints.bytes_per_row_divisor);
for (uint32_t i = 0; i < buffer_collection.buffers.buffer_count; i++) {
EXPECT_TRUE(buffer_collection.buffers.buffers.at(i).vmo.is_valid());
}
EXPECT_FALSE(
buffer_collection.buffers.buffers.at(buffer_collection.buffers.buffer_count).vmo.is_valid());
}
// Validate FR --> GDC1
TEST_F(ControllerMemoryAllocatorTest, VideoConfigFRGDC1) {
auto internal_config = VideoConfigFullRes(false);
auto fr_constraints = *internal_config.output_constraints;
auto gdc1_constraints = *internal_config.child_nodes[0].input_constraints;
BufferCollection buffer_collection;
std::vector<fuchsia::sysmem::BufferCollectionConstraints> constraints;
constraints.push_back(fr_constraints);
constraints.push_back(gdc1_constraints);
RelaxMemoryConstraints(constraints);
ASSERT_EQ(ZX_OK, controller_memory_allocator_->AllocateSharedMemory(
constraints, buffer_collection, "TestVideoConfigFRGDC1"));
EXPECT_GT(buffer_collection.buffers.settings.buffer_settings.size_bytes,
kIspFRWidth * kIspFRHeight);
EXPECT_TRUE(buffer_collection.buffers.settings.has_image_format_constraints);
EXPECT_EQ(fuchsia::sysmem::PixelFormatType::NV12,
buffer_collection.buffers.settings.image_format_constraints.pixel_format.type);
EXPECT_EQ(kIspFRHeight,
buffer_collection.buffers.settings.image_format_constraints.required_max_coded_height);
EXPECT_EQ(kIspFRWidth,
buffer_collection.buffers.settings.image_format_constraints.required_max_coded_width);
EXPECT_EQ(kIspBytesPerRowDivisor,
buffer_collection.buffers.settings.image_format_constraints.bytes_per_row_divisor);
for (uint32_t i = 0; i < buffer_collection.buffers.buffer_count; i++) {
EXPECT_TRUE(buffer_collection.buffers.buffers.at(i).vmo.is_valid());
}
EXPECT_FALSE(
buffer_collection.buffers.buffers.at(buffer_collection.buffers.buffer_count).vmo.is_valid());
}
// Validate GDC1 ---> GDC2
// |
// ---> GE2D
TEST_F(ControllerMemoryAllocatorTest, VideoConfigGDC1GDC2) {
auto input_node = VideoConfigFullRes(false);
auto gdc1_node = input_node.child_nodes[0];
auto gdc2_node = gdc1_node.child_nodes[0];
auto ge2d_node = gdc1_node.child_nodes[1];
auto gdc1_constraints = *gdc1_node.output_constraints;
auto gdc2_constraints = *gdc2_node.input_constraints;
auto ge2d_constraints = *ge2d_node.input_constraints;
BufferCollection buffer_collection;
std::vector<fuchsia::sysmem::BufferCollectionConstraints> constraints;
constraints.push_back(gdc1_constraints);
constraints.push_back(gdc2_constraints);
constraints.push_back(ge2d_constraints);
RelaxMemoryConstraints(constraints);
ASSERT_EQ(ZX_OK, controller_memory_allocator_->AllocateSharedMemory(
constraints, buffer_collection, "TestVideoConfigGDC1GDC2"));
EXPECT_GT(buffer_collection.buffers.settings.buffer_settings.size_bytes,
kGdcFRWidth * kGdcFRHeight);
EXPECT_TRUE(buffer_collection.buffers.settings.has_image_format_constraints);
EXPECT_EQ(fuchsia::sysmem::PixelFormatType::NV12,
buffer_collection.buffers.settings.image_format_constraints.pixel_format.type);
EXPECT_EQ(kGdcFRHeight,
buffer_collection.buffers.settings.image_format_constraints.required_max_coded_height);
EXPECT_EQ(kGdcFRWidth,
buffer_collection.buffers.settings.image_format_constraints.required_max_coded_width);
EXPECT_EQ(kGe2dBytesPerRowDivisor,
buffer_collection.buffers.settings.image_format_constraints.bytes_per_row_divisor);
for (uint32_t i = 0; i < buffer_collection.buffers.buffer_count; i++) {
EXPECT_TRUE(buffer_collection.buffers.buffers.at(i).vmo.is_valid());
}
EXPECT_FALSE(
buffer_collection.buffers.buffers.at(buffer_collection.buffers.buffer_count).vmo.is_valid());
}
// Validate DS --> GDC2 --> (GE2D) --> OutputStreamMonitoring
// This validates only DS --> GDC2
// Buffer collection constraints.
TEST_F(ControllerMemoryAllocatorTest, MonitorConfigDS) {
auto internal_config = MonitorConfigDownScaledRes();
auto ds_constraints = *internal_config.output_constraints;
auto gdc2_constraints = *internal_config.child_nodes[0].input_constraints;
BufferCollection buffer_collection;
std::vector<fuchsia::sysmem::BufferCollectionConstraints> constraints;
constraints.push_back(ds_constraints);
constraints.push_back(gdc2_constraints);
RelaxMemoryConstraints(constraints);
ASSERT_EQ(ZX_OK, controller_memory_allocator_->AllocateSharedMemory(
constraints, buffer_collection, "TestMonitorConfigDS"));
EXPECT_GT(buffer_collection.buffers.settings.buffer_settings.size_bytes,
kOutputStreamDSHeight * kOutputStreamDSWidth);
EXPECT_TRUE(buffer_collection.buffers.settings.has_image_format_constraints);
EXPECT_EQ(fuchsia::sysmem::PixelFormatType::NV12,
buffer_collection.buffers.settings.image_format_constraints.pixel_format.type);
EXPECT_EQ(kIspBytesPerRowDivisor,
buffer_collection.buffers.settings.image_format_constraints.bytes_per_row_divisor);
for (uint32_t i = 0; i < buffer_collection.buffers.buffer_count; i++) {
EXPECT_TRUE(buffer_collection.buffers.buffers.at(i).vmo.is_valid());
}
EXPECT_FALSE(
buffer_collection.buffers.buffers.at(buffer_collection.buffers.buffer_count).vmo.is_valid());
}
TEST_F(ControllerMemoryAllocatorTest, ConvertImageFormat2TypeTest) {
auto internal_config = MonitorConfigFullRes();
auto vector_image_formats = internal_config.image_formats;
fuchsia::sysmem::ImageFormat_2 hlcpp_image_format = vector_image_formats[0];
fuchsia_sysmem::wire::ImageFormat2 c_image_format = ConvertToWireType(hlcpp_image_format);
EXPECT_EQ(c_image_format.pixel_format.type,
static_cast<const fuchsia_sysmem::wire::PixelFormatType>(
hlcpp_image_format.pixel_format.type));
EXPECT_EQ(c_image_format.pixel_format.has_format_modifier,
hlcpp_image_format.pixel_format.has_format_modifier);
EXPECT_EQ(c_image_format.pixel_format.format_modifier.value,
hlcpp_image_format.pixel_format.format_modifier.value);
EXPECT_EQ(c_image_format.coded_width, hlcpp_image_format.coded_width);
EXPECT_EQ(c_image_format.coded_height, hlcpp_image_format.coded_height);
EXPECT_EQ(c_image_format.bytes_per_row, hlcpp_image_format.bytes_per_row);
EXPECT_EQ(c_image_format.display_width, hlcpp_image_format.display_width);
EXPECT_EQ(c_image_format.display_height, hlcpp_image_format.display_height);
EXPECT_EQ(c_image_format.layers, hlcpp_image_format.layers);
EXPECT_EQ(c_image_format.has_pixel_aspect_ratio, hlcpp_image_format.has_pixel_aspect_ratio);
EXPECT_EQ(c_image_format.pixel_aspect_ratio_width, hlcpp_image_format.pixel_aspect_ratio_width);
EXPECT_EQ(c_image_format.pixel_aspect_ratio_height, hlcpp_image_format.pixel_aspect_ratio_height);
}
} // namespace camera