blob: 159b5f838c65417497523ac9cc5609fb4bd02571 [file] [log] [blame] [edit]
// Copyright 2018 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 "src/graphics/display/lib/framebuffer-display/framebuffer-display-driver.h"
#include <fidl/fuchsia.hardware.display.engine/cpp/fidl.h>
#include <fidl/fuchsia.hardware.sysmem/cpp/wire.h>
#include <fidl/fuchsia.sysmem2/cpp/wire.h>
#include <lib/driver/component/cpp/node_add_args.h>
#include <lib/driver/logging/cpp/logger.h>
#include <lib/driver/mmio/cpp/mmio-buffer.h>
#include <lib/fdf/cpp/dispatcher.h>
#include <memory>
#include <bind/fuchsia/cpp/bind.h>
#include <bind/fuchsia/display/cpp/bind.h>
#include <fbl/alloc_checker.h>
#include "src/graphics/display/lib/api-protocols/cpp/display-engine-events-fidl.h"
#include "src/graphics/display/lib/api-protocols/cpp/display-engine-fidl-adapter.h"
#include "src/graphics/display/lib/framebuffer-display/framebuffer-display.h"
namespace framebuffer_display {
FramebufferDisplayDriver::FramebufferDisplayDriver(
std::string_view device_name, fdf::DriverStartArgs start_args,
fdf::UnownedSynchronizedDispatcher driver_dispatcher)
: fdf::DriverBase(device_name, std::move(start_args), std::move(driver_dispatcher)) {}
FramebufferDisplayDriver::~FramebufferDisplayDriver() = default;
zx::result<> FramebufferDisplayDriver::Start() {
zx::result<> configure_hardware_result = ConfigureHardware();
if (configure_hardware_result.is_error()) {
fdf::error("Failed to configure hardware: {}", configure_hardware_result);
return configure_hardware_result.take_error();
}
zx::result<std::unique_ptr<FramebufferDisplay>> framebuffer_display_result =
CreateAndInitializeFramebufferDisplay();
if (framebuffer_display_result.is_error()) {
fdf::error("Failed to create and initialize FramebufferDisplay: {}",
framebuffer_display_result);
return framebuffer_display_result.take_error();
}
framebuffer_display_ = std::move(framebuffer_display_result).value();
zx::result<> add_fidl_service_node_result = InitializeFidlServiceNode();
if (add_fidl_service_node_result.is_error()) {
fdf::error("Failed to add FIDL service node: {}", add_fidl_service_node_result);
return add_fidl_service_node_result.take_error();
}
return zx::ok();
}
void FramebufferDisplayDriver::Stop() {}
zx::result<std::unique_ptr<FramebufferDisplay>>
FramebufferDisplayDriver::CreateAndInitializeFramebufferDisplay() {
fbl::AllocChecker alloc_checker;
engine_events_ = fbl::make_unique_checked<display::DisplayEngineEventsFidl>(&alloc_checker);
if (!alloc_checker.check()) {
fdf::error("Failed to allocate memory for DisplayEngineEventsFidl");
return zx::error(ZX_ERR_NO_MEMORY);
}
zx::result<fdf::MmioBuffer> frame_buffer_mmio_result = GetFrameBufferMmioBuffer();
if (frame_buffer_mmio_result.is_error()) {
fdf::error("Failed to get frame buffer mmio buffer: {}", frame_buffer_mmio_result);
return frame_buffer_mmio_result.take_error();
}
fdf::MmioBuffer frame_buffer_mmio = std::move(frame_buffer_mmio_result).value();
zx::result<DisplayProperties> display_properties_result = GetDisplayProperties();
if (display_properties_result.is_error()) {
fdf::error("Failed to get display properties: {}", display_properties_result);
return display_properties_result.take_error();
}
DisplayProperties display_properties = std::move(display_properties_result).value();
zx::result<fidl::ClientEnd<fuchsia_hardware_sysmem::Sysmem>> sysmem_hardware_client_result =
incoming()->Connect<fuchsia_hardware_sysmem::Sysmem>();
if (sysmem_hardware_client_result.is_error()) {
fdf::error("Failed to get hardware sysmem protocol: {}", sysmem_hardware_client_result);
return sysmem_hardware_client_result.take_error();
}
fidl::WireSyncClient<fuchsia_hardware_sysmem::Sysmem> sysmem_hardware_client(
std::move(sysmem_hardware_client_result).value());
zx::result<fidl::ClientEnd<fuchsia_sysmem2::Allocator>> sysmem_client_result =
incoming()->Connect<fuchsia_sysmem2::Allocator>();
if (sysmem_client_result.is_error()) {
fdf::error("Failed to get fuchsia.sysmem2.Allocator protocol: {}", sysmem_client_result);
return sysmem_client_result.take_error();
}
fidl::WireSyncClient<fuchsia_sysmem2::Allocator> sysmem_client(
std::move(sysmem_client_result).value());
zx::result<fdf::SynchronizedDispatcher> create_dispatcher_result =
fdf::SynchronizedDispatcher::Create(fdf::SynchronizedDispatcher::Options::kAllowSyncCalls,
"framebuffer-display-dispatcher",
[](fdf_dispatcher_t*) {});
if (create_dispatcher_result.is_error()) {
fdf::error("Failed to create framebuffer display dispatcher: {}", create_dispatcher_result);
return create_dispatcher_result.take_error();
}
framebuffer_display_dispatcher_ = std::move(create_dispatcher_result).value();
auto framebuffer_display = fbl::make_unique_checked<FramebufferDisplay>(
&alloc_checker, engine_events_.get(), std::move(sysmem_client),
std::move(sysmem_hardware_client), std::move(frame_buffer_mmio),
std::move(display_properties), framebuffer_display_dispatcher_.async_dispatcher());
if (!alloc_checker.check()) {
fdf::error("Failed to allocate memory for FramebufferDisplay");
return zx::error(ZX_ERR_NO_MEMORY);
}
engine_fidl_adapter_ = fbl::make_unique_checked<display::DisplayEngineFidlAdapter>(
&alloc_checker, framebuffer_display.get(), engine_events_.get());
if (!alloc_checker.check()) {
fdf::error("Failed to allocate memory for DisplayEngineFidlAdapter");
return zx::error(ZX_ERR_NO_MEMORY);
}
zx::result<> framebuffer_display_initialize_result = framebuffer_display->Initialize();
if (framebuffer_display_initialize_result.is_error()) {
fdf::error("Failed to initialize FramebufferDisplay: {}",
framebuffer_display_initialize_result);
return framebuffer_display_initialize_result.take_error();
}
return zx::ok(std::move(framebuffer_display));
}
zx::result<> FramebufferDisplayDriver::InitializeFidlServiceNode() {
ZX_DEBUG_ASSERT(framebuffer_display_ != nullptr);
ZX_DEBUG_ASSERT(engine_fidl_adapter_ != nullptr);
// Serve `fuchsia.hardware.display.engine/Service` at the outgoing directory.
fuchsia_hardware_display_engine::Service::InstanceHandler service_handler(
{.engine = engine_fidl_adapter_->CreateHandler(*(driver_dispatcher()->get()))});
zx::result<> add_service_result =
outgoing()->AddService<fuchsia_hardware_display_engine::Service>(std::move(service_handler));
if (add_service_result.is_error()) {
fdf::error("Failed to add service: {}", add_service_result);
return add_service_result.take_error();
}
const fuchsia_driver_framework::NodeProperty node_properties[] = {
fdf::MakeProperty(bind_fuchsia::PROTOCOL, bind_fuchsia_display::BIND_PROTOCOL_ENGINE),
};
const std::vector<fuchsia_driver_framework::Offer> node_offers = {
fdf::MakeOffer2<fuchsia_hardware_display_engine::Service>(),
};
zx::result<fidl::ClientEnd<fuchsia_driver_framework::NodeController>>
node_controller_client_result = AddChild(name(), node_properties, node_offers);
if (node_controller_client_result.is_error()) {
fdf::error("Failed to add child node: {}", node_controller_client_result);
return node_controller_client_result.take_error();
}
node_controller_ = fidl::WireSyncClient(std::move(node_controller_client_result).value());
return zx::ok();
}
} // namespace framebuffer_display