| // 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 |