blob: 415533fa70b52625bb8e14fe9457096326a7c9c0 [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/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::sysmem2::BufferCollectionConstraints>& constraints) {
for (auto& c : constraints) {
c.mutable_buffer_memory_constraints()->set_cpu_domain_supported(true);
c.mutable_buffer_memory_constraints()->set_ram_domain_supported(true);
c.mutable_buffer_memory_constraints()->set_inaccessible_domain_supported(true);
c.mutable_buffer_memory_constraints()->set_secure_required(false);
c.mutable_buffer_memory_constraints()->set_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()) {}
void SetUp() override {
ASSERT_EQ(ZX_OK, context_->svc()->Connect(sysmem_allocator_.NewRequest()));
ASSERT_EQ(ZX_OK, zx::event::create(0, &event_));
fuchsia::sysmem2::AllocatorSyncPtr sysmem_allocator_B;
ASSERT_EQ(ZX_OK, context_->svc()->Connect(sysmem_allocator_B.NewRequest()));
controller_memory_allocator_ =
std::make_unique<ControllerMemoryAllocator>(std::move(sysmem_allocator_B));
fuchsia::sysmem2::AllocatorSyncPtr sysmem_allocator_C;
ASSERT_EQ(ZX_OK, context_->svc()->Connect(sysmem_allocator_C.NewRequest()));
pipeline_manager_ = std::make_unique<PipelineManager>(
dispatcher(), std::move(sysmem_allocator_C), 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::sysmem2::AllocatorSyncPtr sysmem_allocator_;
std::unique_ptr<ControllerMemoryAllocator> controller_memory_allocator_;
std::unique_ptr<camera::PipelineManager> pipeline_manager_;
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::sysmem2::BufferCollectionConstraints> constraints;
constraints.emplace_back(fidl::Clone(fr_constraints));
constraints.emplace_back(fidl::Clone(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::images2::PixelFormat::NV12,
buffer_collection.buffers.settings().image_format_constraints().pixel_format());
EXPECT_EQ(
kOutputStreamMlFRHeight,
buffer_collection.buffers.settings().image_format_constraints().required_max_size().height);
EXPECT_EQ(
kOutputStreamMlFRWidth,
buffer_collection.buffers.settings().image_format_constraints().required_max_size().width);
EXPECT_EQ(
kIspBytesPerRowDivisor,
buffer_collection.buffers.settings().image_format_constraints().bytes_per_row_divisor());
for (uint32_t i = 0; i < buffer_collection.buffers.buffers().size(); i++) {
EXPECT_TRUE(buffer_collection.buffers.buffers().at(i).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::sysmem2::BufferCollectionConstraints> constraints;
constraints.emplace_back(fidl::Clone(fr_constraints));
constraints.emplace_back(fidl::Clone(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::images2::PixelFormat::NV12,
buffer_collection.buffers.settings().image_format_constraints().pixel_format());
EXPECT_EQ(
kIspFRHeight,
buffer_collection.buffers.settings().image_format_constraints().required_max_size().height);
EXPECT_EQ(
kIspFRWidth,
buffer_collection.buffers.settings().image_format_constraints().required_max_size().width);
EXPECT_EQ(
kIspBytesPerRowDivisor,
buffer_collection.buffers.settings().image_format_constraints().bytes_per_row_divisor());
for (uint32_t i = 0; i < buffer_collection.buffers.buffers().size(); i++) {
EXPECT_TRUE(buffer_collection.buffers.buffers().at(i).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::sysmem2::BufferCollectionConstraints> constraints;
constraints.emplace_back(fidl::Clone(gdc1_constraints));
constraints.emplace_back(fidl::Clone(gdc2_constraints));
constraints.emplace_back(fidl::Clone(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::images2::PixelFormat::NV12,
buffer_collection.buffers.settings().image_format_constraints().pixel_format());
EXPECT_EQ(
kGdcFRHeight,
buffer_collection.buffers.settings().image_format_constraints().required_max_size().height);
EXPECT_EQ(
kGdcFRWidth,
buffer_collection.buffers.settings().image_format_constraints().required_max_size().width);
EXPECT_EQ(
kGe2dBytesPerRowDivisor,
buffer_collection.buffers.settings().image_format_constraints().bytes_per_row_divisor());
for (uint32_t i = 0; i < buffer_collection.buffers.buffers().size(); i++) {
EXPECT_TRUE(buffer_collection.buffers.buffers().at(i).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::sysmem2::BufferCollectionConstraints> constraints;
constraints.emplace_back(fidl::Clone(ds_constraints));
constraints.emplace_back(fidl::Clone(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::images2::PixelFormat::NV12,
buffer_collection.buffers.settings().image_format_constraints().pixel_format());
EXPECT_EQ(
kIspBytesPerRowDivisor,
buffer_collection.buffers.settings().image_format_constraints().bytes_per_row_divisor());
for (uint32_t i = 0; i < buffer_collection.buffers.buffers().size(); i++) {
EXPECT_TRUE(buffer_collection.buffers.buffers().at(i).vmo().is_valid());
}
}
TEST_F(ControllerMemoryAllocatorTest, ConvertImageFormat2TypeTest) {
auto internal_config = MonitorConfigFullRes();
auto& vector_image_formats = internal_config.image_formats;
fuchsia::images2::ImageFormat& hlcpp_image_format = vector_image_formats[0];
fuchsia_sysmem::wire::ImageFormat2 c_image_format = ConvertV2ToV1WireType(hlcpp_image_format);
EXPECT_EQ(c_image_format.pixel_format.type,
static_cast<const fuchsia_sysmem::wire::PixelFormatType>(
static_cast<uint32_t>(hlcpp_image_format.pixel_format())));
EXPECT_EQ(c_image_format.pixel_format.has_format_modifier,
hlcpp_image_format.has_pixel_format_modifier());
if (hlcpp_image_format.has_pixel_format_modifier()) {
EXPECT_EQ(c_image_format.pixel_format.format_modifier.value,
hlcpp_image_format.pixel_format_modifier());
}
EXPECT_EQ(c_image_format.coded_width, hlcpp_image_format.size().width);
EXPECT_EQ(c_image_format.coded_height, hlcpp_image_format.size().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_rect().width);
EXPECT_EQ(c_image_format.display_height, hlcpp_image_format.display_rect().height);
EXPECT_EQ(c_image_format.layers, 1u);
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