blob: 03a576403fa6e0dd12e181ef1c8797ee076609a0 [file] [log] [blame]
// Copyright 2023 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/drivers/coordinator/engine-driver-client.h"
#include <fuchsia/hardware/display/controller/c/banjo.h>
#include <lib/driver/compat/cpp/banjo_client.h>
#include <lib/zx/channel.h>
#include <lib/zx/result.h>
#include <zircon/assert.h>
#include <zircon/errors.h>
#include <zircon/status.h>
#include <cstdint>
#include <fbl/alloc_checker.h>
#include "src/graphics/display/lib/api-types-cpp/display-id.h"
#include "src/graphics/display/lib/api-types-cpp/driver-buffer-collection-id.h"
#include "src/graphics/display/lib/api-types-cpp/driver-buffer-id.h"
#include "src/graphics/display/lib/api-types-cpp/driver-capture-image-id.h"
#include "src/graphics/display/lib/api-types-cpp/driver-image-id.h"
#include "src/graphics/display/lib/api-types-cpp/image-buffer-usage.h"
#include "src/graphics/display/lib/api-types-cpp/image-id.h"
#include "src/graphics/display/lib/api-types-cpp/image-metadata.h"
#include "src/graphics/display/lib/driver-framework-migration-utils/logging/zxlogf.h"
namespace display {
namespace {
static constexpr fdf_arena_tag_t kArenaTag = 'DISP';
zx::result<std::unique_ptr<EngineDriverClient>> CreateFidlEngineDriverClient(
fdf::Namespace& incoming) {
zx::result<fdf::ClientEnd<fuchsia_hardware_display_engine::Engine>> connect_engine_client_result =
incoming.Connect<fuchsia_hardware_display_engine::Service::Engine>();
if (connect_engine_client_result.is_error()) {
zxlogf(WARNING, "Failed to connect to display engine FIDL client: %s",
connect_engine_client_result.status_string());
return connect_engine_client_result.take_error();
}
fdf::ClientEnd<fuchsia_hardware_display_engine::Engine> engine_client =
std::move(connect_engine_client_result).value();
if (!engine_client.is_valid()) {
zxlogf(WARNING, "Display engine FIDL device is invalid");
return zx::error(ZX_ERR_BAD_HANDLE);
}
fdf::Arena arena(kArenaTag);
fdf::WireUnownedResult result = fdf::WireCall(engine_client).buffer(arena)->IsAvailable();
if (!result.ok()) {
zxlogf(WARNING, "Display engine FIDL device is not available: %s",
result.FormatDescription().c_str());
return zx::error(result.status());
}
fbl::AllocChecker alloc_checker;
auto engine_driver_client =
fbl::make_unique_checked<EngineDriverClient>(&alloc_checker, std::move(engine_client));
if (!alloc_checker.check()) {
zxlogf(WARNING, "Failed to allocate memory for EngineDriverClient");
return zx::error(ZX_ERR_NO_MEMORY);
}
return zx::ok(std::move(engine_driver_client));
}
zx::result<std::unique_ptr<EngineDriverClient>> CreateBanjoEngineDriverClient(
std::shared_ptr<fdf::Namespace> incoming) {
zx::result dc_result = compat::ConnectBanjo<ddk::DisplayControllerImplProtocolClient>(incoming);
if (dc_result.is_error()) {
zxlogf(WARNING, "Failed to connect to Banjo server via the compat client: %s",
dc_result.status_string());
}
ddk::DisplayControllerImplProtocolClient dc = std::move(dc_result).value();
if (!dc.is_valid()) {
zxlogf(WARNING, "Failed to get Banjo display controller protocol");
return zx::error(ZX_ERR_NOT_SUPPORTED);
}
fbl::AllocChecker alloc_checker;
auto engine_driver_client =
fbl::make_unique_checked<EngineDriverClient>(&alloc_checker, std::move(dc));
if (!alloc_checker.check()) {
zxlogf(WARNING, "Failed to allocate memory for EngineDriverClient");
return zx::error(ZX_ERR_NO_MEMORY);
}
return zx::ok(std::move(engine_driver_client));
}
} // namespace
// static
zx::result<std::unique_ptr<EngineDriverClient>> EngineDriverClient::Create(
std::shared_ptr<fdf::Namespace> incoming) {
ZX_DEBUG_ASSERT(incoming != nullptr);
// Attempt to connect to FIDL protocol.
zx::result<std::unique_ptr<EngineDriverClient>> fidl_engine_driver_client_result =
CreateFidlEngineDriverClient(*incoming);
if (fidl_engine_driver_client_result.is_ok()) {
zxlogf(INFO, "Using the FIDL Engine driver client");
return fidl_engine_driver_client_result.take_value();
}
zxlogf(WARNING, "Failed to create FIDL Engine driver client: %s; fallback to banjo",
fidl_engine_driver_client_result.status_string());
// Fallback to Banjo protocol.
zx::result<std::unique_ptr<EngineDriverClient>> banjo_engine_driver_client_result =
CreateBanjoEngineDriverClient(incoming);
if (banjo_engine_driver_client_result.is_error()) {
zxlogf(ERROR, "Failed to create banjo Engine driver client: %s",
banjo_engine_driver_client_result.status_string());
}
return banjo_engine_driver_client_result;
}
EngineDriverClient::EngineDriverClient(ddk::DisplayControllerImplProtocolClient dc)
: use_engine_(false), dc_(dc) {
ZX_DEBUG_ASSERT(dc_.is_valid());
}
EngineDriverClient::EngineDriverClient(
fdf::ClientEnd<fuchsia_hardware_display_engine::Engine> engine)
: use_engine_(true), engine_(std::move(engine)) {
ZX_DEBUG_ASSERT(engine_.is_valid());
}
EngineDriverClient::~EngineDriverClient() {
zxlogf(TRACE, "EngineDriverClient::~EngineDriverClient");
}
void EngineDriverClient::ReleaseImage(DriverImageId driver_image_id) {
if (use_engine_) {
fdf::Arena arena(kArenaTag);
fdf::WireUnownedResult result =
engine_.buffer(arena)->ReleaseImage(ToFidlDriverImageId(driver_image_id));
if (!result.ok()) {
zxlogf(ERROR, "ReleaseImage failed: %s", result.status_string());
}
return;
}
ZX_DEBUG_ASSERT(dc_.is_valid());
dc_.ReleaseImage(ToBanjoDriverImageId(driver_image_id));
}
zx::result<> EngineDriverClient::ReleaseCapture(DriverCaptureImageId driver_capture_image_id) {
if (use_engine_) {
fdf::Arena arena(kArenaTag);
fdf::WireUnownedResult result =
engine_.buffer(arena)->ReleaseCapture(ToFidlDriverCaptureImageId(driver_capture_image_id));
return zx::make_result(result.status());
}
ZX_DEBUG_ASSERT(dc_.is_valid());
zx_status_t banjo_status =
dc_.ReleaseCapture(ToBanjoDriverCaptureImageId(driver_capture_image_id));
return zx::make_result(banjo_status);
}
config_check_result_t EngineDriverClient::CheckConfiguration(
const display_config_t* display_config_list, size_t display_config_count,
client_composition_opcode_t* out_client_composition_opcodes_list,
size_t client_composition_opcodes_count, size_t* out_client_composition_opcodes_actual) {
if (use_engine_) {
return CONFIG_CHECK_RESULT_UNSUPPORTED_MODES;
}
ZX_DEBUG_ASSERT(dc_.is_valid());
return dc_.CheckConfiguration(
display_config_list, display_config_count, out_client_composition_opcodes_list,
client_composition_opcodes_count, out_client_composition_opcodes_actual);
}
void EngineDriverClient::ApplyConfiguration(const display_config_t* display_config_list,
size_t display_config_count,
const config_stamp_t* config_stamp) {
if (use_engine_) {
return;
}
ZX_DEBUG_ASSERT(dc_.is_valid());
dc_.ApplyConfiguration(display_config_list, display_config_count, config_stamp);
}
void EngineDriverClient::SetDisplayControllerInterface(
const display_controller_interface_protocol_t& protocol) {
if (use_engine_) {
return;
}
ZX_DEBUG_ASSERT(dc_.is_valid());
dc_.SetDisplayControllerInterface(protocol.ctx, protocol.ops);
}
void EngineDriverClient::ResetDisplayControllerInterface() {
if (use_engine_) {
return;
}
ZX_DEBUG_ASSERT(dc_.is_valid());
dc_.ResetDisplayControllerInterface();
}
zx::result<DriverImageId> EngineDriverClient::ImportImage(const ImageMetadata& image_metadata,
DriverBufferCollectionId collection_id,
uint32_t index) {
if (use_engine_) {
return zx::error(ZX_ERR_NOT_SUPPORTED);
}
ZX_DEBUG_ASSERT(dc_.is_valid());
const image_metadata_t banjo_image_metadata = image_metadata.ToBanjo();
uint64_t image_handle = 0;
zx_status_t banjo_status = dc_.ImportImage(
&banjo_image_metadata, ToBanjoDriverBufferCollectionId(collection_id), index, &image_handle);
if (banjo_status != ZX_OK) {
return zx::error(banjo_status);
}
return zx::ok(DriverImageId(image_handle));
}
zx::result<DriverCaptureImageId> EngineDriverClient::ImportImageForCapture(
DriverBufferCollectionId collection_id, uint32_t index) {
if (use_engine_) {
fdf::Arena arena(kArenaTag);
fdf::WireUnownedResult result =
engine_.buffer(arena)->ImportImageForCapture(ToFidlDriverBufferId({
.buffer_collection_id = collection_id,
.buffer_index = index,
}));
if (!result.ok()) {
return zx::error(result.status());
}
if (result->is_error()) {
return zx::error(result->error_value());
}
fuchsia_hardware_display_engine::wire::ImageId image_id = result->value()->capture_image_id;
return zx::ok(ToDriverCaptureImageId(image_id.value));
}
ZX_DEBUG_ASSERT(dc_.is_valid());
uint64_t banjo_capture_image_handle = 0;
zx_status_t banjo_status = dc_.ImportImageForCapture(
ToBanjoDriverBufferCollectionId(collection_id), index, &banjo_capture_image_handle);
if (banjo_status != ZX_OK) {
return zx::error(banjo_status);
}
return zx::ok(ToDriverCaptureImageId(banjo_capture_image_handle));
}
zx::result<> EngineDriverClient::ImportBufferCollection(
DriverBufferCollectionId collection_id,
fidl::ClientEnd<fuchsia_sysmem::BufferCollectionToken> collection_token) {
if (use_engine_) {
return zx::error(ZX_ERR_NOT_SUPPORTED);
}
ZX_DEBUG_ASSERT(dc_.is_valid());
zx_status_t banjo_status = dc_.ImportBufferCollection(
ToBanjoDriverBufferCollectionId(collection_id), std::move(collection_token).TakeChannel());
return zx::make_result(banjo_status);
}
zx::result<> EngineDriverClient::ReleaseBufferCollection(DriverBufferCollectionId collection_id) {
if (use_engine_) {
return zx::error(ZX_ERR_NOT_SUPPORTED);
}
ZX_DEBUG_ASSERT(dc_.is_valid());
zx_status_t banjo_status =
dc_.ReleaseBufferCollection(ToBanjoDriverBufferCollectionId(collection_id));
return zx::make_result(banjo_status);
}
zx::result<> EngineDriverClient::SetBufferCollectionConstraints(
const ImageBufferUsage& usage, DriverBufferCollectionId collection_id) {
if (use_engine_) {
return zx::error(ZX_ERR_NOT_SUPPORTED);
}
ZX_DEBUG_ASSERT(dc_.is_valid());
const image_buffer_usage_t banjo_usage = ToBanjoImageBufferUsage(usage);
zx_status_t banjo_status = dc_.SetBufferCollectionConstraints(
&banjo_usage, ToBanjoDriverBufferCollectionId(collection_id));
return zx::make_result(banjo_status);
}
bool EngineDriverClient::IsCaptureSupported() {
if (use_engine_) {
return false;
}
ZX_DEBUG_ASSERT(dc_.is_valid());
return dc_.IsCaptureSupported();
}
zx::result<> EngineDriverClient::StartCapture(DriverCaptureImageId driver_capture_image_id) {
if (use_engine_) {
return zx::error(ZX_ERR_NOT_SUPPORTED);
}
ZX_DEBUG_ASSERT(dc_.is_valid());
zx_status_t banjo_status = dc_.StartCapture(ToBanjoDriverCaptureImageId(driver_capture_image_id));
return zx::make_result(banjo_status);
}
zx::result<> EngineDriverClient::SetDisplayPower(DisplayId display_id, bool power_on) {
if (use_engine_) {
return zx::error(ZX_ERR_NOT_SUPPORTED);
}
ZX_DEBUG_ASSERT(dc_.is_valid());
zx_status_t banjo_status = dc_.SetDisplayPower(ToBanjoDisplayId(display_id), power_on);
return zx::make_result(banjo_status);
}
zx::result<> EngineDriverClient::SetMinimumRgb(uint8_t minimum_rgb) {
if (use_engine_) {
return zx::error(ZX_ERR_NOT_SUPPORTED);
}
ZX_DEBUG_ASSERT(dc_.is_valid());
zx_status_t banjo_status = dc_.SetMinimumRgb(minimum_rgb);
return zx::make_result(banjo_status);
}
} // namespace display