diff --git a/garnet/bin/display_capture_test/BUILD.gn b/garnet/bin/display_capture_test/BUILD.gn index 6526f7bb24381959d6bbf029a2da10eaa33b3587..aa25a07ba7c3bf1edad4f156cba23ff946fae702 100644 --- a/garnet/bin/display_capture_test/BUILD.gn +++ b/garnet/bin/display_capture_test/BUILD.gn @@ -29,6 +29,7 @@ executable("bin") { "//garnet/public/lib/fsl", "//zircon/public/fidl/fuchsia-hardware-camera:fuchsia-hardware-camera_c", "//zircon/public/fidl/fuchsia-hardware-display", + "//zircon/public/fidl/fuchsia-hardware-display:fuchsia-hardware-display_c", "//zircon/public/lib/async-loop-cpp", "//zircon/public/lib/fzl", ] diff --git a/garnet/bin/display_capture_test/runner.cc b/garnet/bin/display_capture_test/runner.cc index 7a30e3326eae7c90e1516b8866871906f0e6067e..80bcfc7821f363b0422585e848e4f7a54289343e 100644 --- a/garnet/bin/display_capture_test/runner.cc +++ b/garnet/bin/display_capture_test/runner.cc @@ -8,8 +8,10 @@ #include <fbl/unique_fd.h> #include <fcntl.h> #include <fuchsia/hardware/camera/c/fidl.h> +#include <fuchsia/hardware/display/c/fidl.h> #include <lib/fzl/fdio.h> #include <zircon/device/display-controller.h> + #include <cmath> namespace display_test { @@ -204,19 +206,38 @@ void Runner::GetFormatCallback(::std::vector<fuchsia::camera::VideoFormat> fmts, void Runner::InitDisplay() { zx_status_t status; - fxl::UniqueFD fd(open(kDisplayController, O_RDWR)); + fbl::unique_fd fd(open(kDisplayController, O_RDWR)); if (!fd.is_valid()) { ZX_ASSERT_MSG(false, "Failed to open display controller"); } - zx::channel dc_handle; - if (ioctl_display_controller_get_handle( - fd.get(), dc_handle.reset_and_get_address()) != sizeof(zx_handle_t)) { - ZX_ASSERT_MSG(false, "Failed to obtain display controller handle"); + zx::channel device_server, device_client; + status = zx::channel::create(0, &device_server, &device_client); + if (status != ZX_OK) { + ZX_ASSERT_MSG(false, "Failed to create device channel %d\n", status); + } + + zx::channel dc_server, dc_client; + status = zx::channel::create(0, &dc_server, &dc_client); + if (status != ZX_OK) { + ZX_ASSERT_MSG(false, "Failed to get create controller channel %d\n", + status); + } + + fzl::FdioCaller dev(std::move(fd)); + zx_status_t fidl_status = fuchsia_hardware_display_ProviderOpenController( + dev.borrow_channel(), device_server.release(), dc_server.release(), + &status); + if (fidl_status != ZX_OK) { + ZX_ASSERT_MSG(false, "Failed to call service handle %d\n", status); } + if (status != ZX_OK) { + ZX_ASSERT_MSG(false, "Failed to open controller %d\n", status); + } + + display_controller_conn_ = std::move(device_client); - dc_fd_ = std::move(fd); - if ((status = display_controller_.Bind(std::move(dc_handle), + if ((status = display_controller_.Bind(std::move(dc_client), loop_->dispatcher())) != ZX_OK) { ZX_ASSERT_MSG(false, "Failed to bind to display controller %d\n", status); } diff --git a/garnet/bin/display_capture_test/runner.h b/garnet/bin/display_capture_test/runner.h index 282dc693feb5007d05b46697461c93efea575e39..7493622ba1756ca76067852f0e2c69f70b8bd205 100644 --- a/garnet/bin/display_capture_test/runner.h +++ b/garnet/bin/display_capture_test/runner.h @@ -11,14 +11,15 @@ #include <lib/async-loop/cpp/loop.h> #include <lib/fidl/cpp/synchronous_interface_ptr.h> #include <lib/fsl/io/device_watcher.h> -#include "src/lib/files/unique_fd.h" #include <zircon/pixelformat.h> #include <zircon/types.h> + #include <deque> #include "context.h" #include "image.h" #include "layer.h" +#include "src/lib/files/unique_fd.h" namespace display_test { @@ -61,9 +62,8 @@ class Runner { void FrameNotifyCallback(const fuchsia::camera::FrameAvailableEvent& resp); void InitDisplay(); - void OnDisplaysChanged( - ::std::vector<fuchsia::hardware::display::Info> added, - ::std::vector<uint64_t> removed); + void OnDisplaysChanged(::std::vector<fuchsia::hardware::display::Info> added, + ::std::vector<uint64_t> removed); void OnClientOwnershipChange(bool is_owner); void OnVsync(uint64_t display_id, uint64_t timestamp, ::std::vector<uint64_t> image_ids); @@ -82,7 +82,7 @@ class Runner { PrimaryLayer* calibration_layer_; const char* display_name_; - fxl::UniqueFD dc_fd_; + zx::channel display_controller_conn_; fuchsia::hardware::display::ControllerPtr display_controller_; uint64_t display_id_ = 0; diff --git a/garnet/lib/ui/gfx/BUILD.gn b/garnet/lib/ui/gfx/BUILD.gn index 8395d6a1163aa893476795441760d2336f7e2edb..6e44e040dcf617ea02c959b241ba24362c017dbc 100644 --- a/garnet/lib/ui/gfx/BUILD.gn +++ b/garnet/lib/ui/gfx/BUILD.gn @@ -220,6 +220,7 @@ source_set("gfx") { "//sdk/lib/sys/cpp", "//src/lib/fxl", "//zircon/public/fidl/fuchsia-hardware-display", + "//zircon/public/fidl/fuchsia-hardware-display:fuchsia-hardware-display_c", "//zircon/public/lib/fit", ] @@ -231,6 +232,8 @@ source_set("gfx") { "//garnet/public/lib/ui/scenic/cpp", "//zircon/public/fidl/fuchsia-scheduler", "//zircon/public/fidl/fuchsia-sysmem", + "//zircon/public/lib/fbl", + "//zircon/public/lib/fzl", "//zircon/public/lib/trace", ] } diff --git a/garnet/lib/ui/gfx/displays/display_manager.cc b/garnet/lib/ui/gfx/displays/display_manager.cc index b1d618aa1014a2eeb91bdc93a797adaebcc1a055..88ee6b8704e223765e72be02d53cec37ac7079b7 100644 --- a/garnet/lib/ui/gfx/displays/display_manager.cc +++ b/garnet/lib/ui/gfx/displays/display_manager.cc @@ -8,6 +8,7 @@ #include <lib/fdio/directory.h> #include <trace/event.h> #include <zircon/syscalls.h> + #include "fuchsia/ui/scenic/cpp/fidl.h" namespace scenic_impl { @@ -34,8 +35,8 @@ void DisplayManager::WaitForDefaultDisplay(fit::closure callback) { display_available_cb_ = std::move(callback); display_watcher_.WaitForDisplay( - [this](fxl::UniqueFD fd, zx::channel dc_handle) { - dc_fd_ = std::move(fd); + [this](zx::channel device, zx::channel dc_handle) { + dc_device_ = std::move(device); dc_channel_ = dc_handle.get(); display_controller_.Bind(std::move(dc_handle)); diff --git a/garnet/lib/ui/gfx/displays/display_manager.h b/garnet/lib/ui/gfx/displays/display_manager.h index 30327dcbdca9c661fa7c8504ba6d1fa385dd95a4..bd4a0856154f0cbde84c2483b9dd2ad2e34a1923 100644 --- a/garnet/lib/ui/gfx/displays/display_manager.h +++ b/garnet/lib/ui/gfx/displays/display_manager.h @@ -5,6 +5,10 @@ #ifndef GARNET_LIB_UI_GFX_DISPLAYS_DISPLAY_MANAGER_H_ #define GARNET_LIB_UI_GFX_DISPLAYS_DISPLAY_MANAGER_H_ +#include <lib/fit/function.h> +#include <lib/zx/event.h> +#include <zircon/pixelformat.h> + #include <cstdint> #include "fuchsia/hardware/display/cpp/fidl.h" @@ -14,10 +18,6 @@ #include "lib/async/cpp/wait.h" #include "src/lib/fxl/macros.h" -#include <lib/fit/function.h> -#include <zircon/pixelformat.h> -#include <lib/zx/event.h> - namespace scenic_impl { namespace gfx { @@ -91,7 +91,7 @@ class DisplayManager { ::std::vector<uint64_t> removed); void ClientOwnershipChange(bool has_ownership); - fxl::UniqueFD dc_fd_; + zx::channel dc_device_; fuchsia::hardware::display::ControllerSyncPtr display_controller_; fidl::InterfacePtr<fuchsia::hardware::display::Controller> event_dispatcher_; zx_handle_t dc_channel_; // display_controller_ owns the zx::channel diff --git a/garnet/lib/ui/gfx/displays/display_watcher.cc b/garnet/lib/ui/gfx/displays/display_watcher.cc index 8176becd6d844c87948b4a3b2f6a2ca8eb51191b..7f5b33dd359cd25fd768f2cc15d58c9b1fd3e830 100644 --- a/garnet/lib/ui/gfx/displays/display_watcher.cc +++ b/garnet/lib/ui/gfx/displays/display_watcher.cc @@ -4,13 +4,13 @@ #include "garnet/lib/ui/gfx/displays/display_watcher.h" +#include <fbl/unique_fd.h> #include <fcntl.h> - +#include <fuchsia/hardware/display/c/fidl.h> #include <lib/fidl/cpp/message.h> -#include <zircon/device/display-controller.h> - -#include "src/lib/fxl/logging.h" -#include "src/lib/files/unique_fd.h" +#include <lib/fzl/fdio.h> +#include <src/lib/fxl/logging.h> +#include <zircon/status.h> namespace scenic_impl { namespace gfx { @@ -39,22 +39,49 @@ void DisplayWatcher::HandleDevice(DisplayReadyCallback callback, int dir_fd, FXL_LOG(INFO) << "Scenic: Acquired display controller " << path << ".(" << filename << ")"; - fxl::UniqueFD fd(open(path.c_str(), O_RDWR)); + fbl::unique_fd fd(open(path.c_str(), O_RDWR)); if (!fd.is_valid()) { FXL_DLOG(ERROR) << "Failed to open " << path << ": errno=" << errno; - callback(fxl::UniqueFD(), zx::channel()); + callback(zx::channel(), zx::channel()); + return; + } + + zx::channel device_server, device_client; + zx_status_t status = zx::channel::create(0, &device_server, &device_client); + if (status != ZX_OK) { + FXL_DLOG(ERROR) << "Failed to create device channel: " + << zx_status_get_string(status); + callback(zx::channel(), zx::channel()); return; } - zx::channel dc_handle; - if (ioctl_display_controller_get_handle( - fd.get(), dc_handle.reset_and_get_address()) != sizeof(zx_handle_t)) { - FXL_DLOG(ERROR) << "Failed to get device channel"; - callback(fxl::UniqueFD(), zx::channel()); + zx::channel dc_server, dc_client; + status = zx::channel::create(0, &dc_server, &dc_client); + if (status != ZX_OK) { + FXL_DLOG(ERROR) << "Failed to create controller channel: " + << zx_status_get_string(status); + callback(zx::channel(), zx::channel()); + return; + } + + fzl::FdioCaller caller(std::move(fd)); + zx_status_t fidl_status = fuchsia_hardware_display_ProviderOpenController( + caller.borrow_channel(), device_server.release(), dc_server.release(), + &status); + if (fidl_status != ZX_OK) { + FXL_DLOG(ERROR) << "Failed to call service handle: " + << zx_status_get_string(fidl_status); + callback(zx::channel(), zx::channel()); + return; + } + if (status != ZX_OK) { + FXL_DLOG(ERROR) << "Failed to open controller : " + << zx_status_get_string(status); + callback(zx::channel(), zx::channel()); return; } - callback(std::move(fd), std::move(dc_handle)); + callback(std::move(device_client), std::move(dc_client)); } } // namespace gfx diff --git a/garnet/lib/ui/gfx/displays/display_watcher.h b/garnet/lib/ui/gfx/displays/display_watcher.h index 777a32b34d82080ca271084a12c72f841fc51d14..b647ea0a68e3f1ea72c126ca1442a5f2f6900712 100644 --- a/garnet/lib/ui/gfx/displays/display_watcher.h +++ b/garnet/lib/ui/gfx/displays/display_watcher.h @@ -5,13 +5,10 @@ #ifndef GARNET_LIB_UI_GFX_DISPLAYS_DISPLAY_WATCHER_H_ #define GARNET_LIB_UI_GFX_DISPLAYS_DISPLAY_WATCHER_H_ -#include <memory> - #include <lib/fit/function.h> - -#include "lib/fsl/io/device_watcher.h" -#include "src/lib/fxl/macros.h" -#include "lib/zx/event.h" +#include <lib/fsl/io/device_watcher.h> +#include <memory> +#include <src/lib/fxl/macros.h> namespace scenic_impl { namespace gfx { @@ -20,10 +17,10 @@ namespace gfx { // attributes through a callback. class DisplayWatcher { public: - // Callback that accepts display metrics. - // |metrics| may be null if the display was not successfully acquired. + // Callback provides channels to the display controller device and FIDL + // interface. using DisplayReadyCallback = - fit::function<void(fxl::UniqueFD fd, zx::channel dc_handle)>; + fit::function<void(zx::channel device, zx::channel controller)>; DisplayWatcher(); ~DisplayWatcher(); diff --git a/garnet/lib/ui/gfx/tests/meta/mock_pose_buffer_provider.cmx b/garnet/lib/ui/gfx/tests/meta/mock_pose_buffer_provider.cmx index b548c5ddb84983e3f51243a0bec59801b5734b79..3540a15e47be387f23029ffeabdf467fa6438f1e 100644 --- a/garnet/lib/ui/gfx/tests/meta/mock_pose_buffer_provider.cmx +++ b/garnet/lib/ui/gfx/tests/meta/mock_pose_buffer_provider.cmx @@ -3,6 +3,9 @@ "binary": "bin/app" }, "sandbox": { + "dev": [ + "class/display-controller" + ], "services": [ "fuchsia.tracelink.Registry", "fuchsia.ui.scenic.Scenic" diff --git a/garnet/lib/vulkan/src/swapchain/BUILD.gn b/garnet/lib/vulkan/src/swapchain/BUILD.gn index cb48a303c74b2e16a01fb572606f90909da9ba7c..04136c3a22a81cae161519684a648a9461de7271 100644 --- a/garnet/lib/vulkan/src/swapchain/BUILD.gn +++ b/garnet/lib/vulkan/src/swapchain/BUILD.gn @@ -55,10 +55,13 @@ loadable_module("fb") { "$loader_build_root:extra_vulkan_headers", "$loader_build_root/layers:micro_layer_common", "//zircon/public/fidl/fuchsia-hardware-display", + "//zircon/public/fidl/fuchsia-hardware-display:fuchsia-hardware-display_c", "//zircon/public/fidl/fuchsia-sysmem", "//zircon/public/lib/async-cpp", "//zircon/public/lib/async-loop-cpp", + "//zircon/public/lib/fbl", "//zircon/public/lib/fdio", + "//zircon/public/lib/fzl", ] ldflags = [ "-static-libstdc++" ] } diff --git a/garnet/lib/vulkan/src/swapchain/image_pipe_surface_display.cc b/garnet/lib/vulkan/src/swapchain/image_pipe_surface_display.cc index 2f550f4b565dcff20fe9d092be87745fd2fabceb..30d0a1cb24f86fbcabb68d91e29a05eac7206186 100644 --- a/garnet/lib/vulkan/src/swapchain/image_pipe_surface_display.cc +++ b/garnet/lib/vulkan/src/swapchain/image_pipe_surface_display.cc @@ -3,17 +3,22 @@ // found in the LICENSE file. #include "image_pipe_surface_display.h" + +#include <fbl/unique_fd.h> #include <fcntl.h> +#include <fuchsia/hardware/display/c/fidl.h> #include <lib/async/cpp/task.h> #include <lib/fdio/directory.h> -#include <zircon/device/display-controller.h> +#include <lib/fzl/fdio.h> +#include <limits.h> #include <zircon/pixelformat.h> +#include <zircon/status.h> + #include <cstdio> + #include "vk_dispatch_table_helper.h" #include "vulkan/vk_layer.h" -#include <limits.h> - namespace image_pipe_swapchain { ImagePipeSurfaceDisplay::ImagePipeSurfaceDisplay() @@ -28,24 +33,47 @@ bool ImagePipeSurfaceDisplay::Init() { fprintf(stderr, "Couldn't connect to sysmem service\n"); return false; } - int dc_fd = open("/dev/class/display-controller/000", O_RDWR); - if (dc_fd < 0) { + + fbl::unique_fd fd(open("/dev/class/display-controller/000", O_RDWR)); + if (!fd) { fprintf(stderr, "No display controller\n"); return false; } - zx_handle_t dc_handle; + zx::channel device_server, device_client; + status = zx::channel::create(0, &device_server, &device_client); + if (status != ZX_OK) { + fprintf(stderr, "Failed to create device channel %d (%s)\n", status, + zx_status_get_string(status)); + return false; + } - if (ioctl_display_controller_get_handle(dc_fd, &dc_handle) != - sizeof(zx_handle_t)) { - close(dc_fd); - fprintf(stderr, "No display controller 2\n"); + zx::channel dc_server, dc_client; + status = zx::channel::create(0, &dc_server, &dc_client); + if (status != ZX_OK) { + fprintf(stderr, "Failed to create controller channel %d (%s)\n", status, + zx_status_get_string(status)); return false; } - dc_fd_ = dc_fd; + fzl::FdioCaller caller(std::move(fd)); + zx_status_t fidl_status = fuchsia_hardware_display_ProviderOpenController( + caller.borrow_channel(), device_server.release(), dc_server.release(), + &status); + if (fidl_status != ZX_OK) { + fprintf(stderr, "Failed to call service handle %d (%s)\n", fidl_status, + zx_status_get_string(fidl_status)); + return false; + } + if (status != ZX_OK) { + fprintf(stderr, "Failed to open controller %d (%s)\n", status, + zx_status_get_string(status)); + return false; + } + + dc_device_ = std::move(device_client); - display_controller_.Bind(zx::channel(dc_handle), loop_.dispatcher()); + display_controller_.Bind(std::move(dc_client), loop_.dispatcher()); display_controller_.set_error_handler( fit::bind_member(this, &ImagePipeSurfaceDisplay::ControllerError)); @@ -60,11 +88,6 @@ bool ImagePipeSurfaceDisplay::Init() { return true; } -ImagePipeSurfaceDisplay::~ImagePipeSurfaceDisplay() { - if (dc_fd_ >= 0) - close(dc_fd_); -} - void ImagePipeSurfaceDisplay::ControllerError(zx_status_t status) { display_connection_exited_ = true; } diff --git a/garnet/lib/vulkan/src/swapchain/image_pipe_surface_display.h b/garnet/lib/vulkan/src/swapchain/image_pipe_surface_display.h index 63cc1324c946ecb5febbf6fbfd0c3ce5fd3825f3..bde3f2da686a4388070c7e8ffacf32f64aaee41c 100644 --- a/garnet/lib/vulkan/src/swapchain/image_pipe_surface_display.h +++ b/garnet/lib/vulkan/src/swapchain/image_pipe_surface_display.h @@ -5,12 +5,13 @@ #ifndef GARNET_LIB_VULKAN_SRC_SWAPCHAIN_IMAGE_PIPE_SURFACE_DISPLAY_H_ #define GARNET_LIB_VULKAN_SRC_SWAPCHAIN_IMAGE_PIPE_SURFACE_DISPLAY_H_ +#include <lib/async-loop/cpp/loop.h> + #include <map> -#include "image_pipe_surface.h" -#include <lib/async-loop/cpp/loop.h> -#include "fuchsia/hardware/display/cpp/fidl.h" -#include "fuchsia/sysmem/cpp/fidl.h" +#include <fuchsia/hardware/display/cpp/fidl.h> +#include <fuchsia/sysmem/cpp/fidl.h> +#include "image_pipe_surface.h" namespace image_pipe_swapchain { @@ -18,7 +19,6 @@ namespace image_pipe_swapchain { class ImagePipeSurfaceDisplay : public ImagePipeSurface { public: ImagePipeSurfaceDisplay(); - ~ImagePipeSurfaceDisplay() override; bool Init() override; @@ -50,7 +50,7 @@ class ImagePipeSurfaceDisplay : public ImagePipeSurface { async::Loop loop_; std::map<uint64_t, uint64_t> image_id_map; - int dc_fd_ = -1; + zx::channel dc_device_; bool display_connection_exited_ = false; bool got_message_response_ = false; bool have_display_ = false; diff --git a/garnet/public/rust/fuchsia-framebuffer/BUILD.gn b/garnet/public/rust/fuchsia-framebuffer/BUILD.gn index fb9cb82abc3258c197bbf207144cf6f7340e8205..ac44d9a1878f317f152b267aac1d35ec846574e8 100644 --- a/garnet/public/rust/fuchsia-framebuffer/BUILD.gn +++ b/garnet/public/rust/fuchsia-framebuffer/BUILD.gn @@ -9,6 +9,7 @@ rustc_library("fuchsia-framebuffer") { version = "0.1.0" edition = "2018" deps = [ + "//garnet/public/lib/fidl/rust/fidl", "//garnet/public/rust/fdio", "//garnet/public/rust/fuchsia-async", "//garnet/public/rust/fuchsia-runtime", diff --git a/garnet/public/rust/fuchsia-framebuffer/src/lib.rs b/garnet/public/rust/fuchsia-framebuffer/src/lib.rs index effa586a401d769f569f4bdbe69925a7675db3b5..b660246a6890663dc88903df6a428489c961eb6a 100644 --- a/garnet/public/rust/fuchsia-framebuffer/src/lib.rs +++ b/garnet/public/rust/fuchsia-framebuffer/src/lib.rs @@ -5,27 +5,26 @@ #![allow(dead_code)] use failure::{format_err, Error, ResultExt}; -use fdio::fdio_sys::{fdio_ioctl, IOCTL_FAMILY_DISPLAY_CONTROLLER, IOCTL_KIND_GET_HANDLE}; -use fdio::make_ioctl; use fdio::watch_directory; -use fidl_fuchsia_hardware_display::{ControllerEvent, ControllerProxy, ImageConfig, ImagePlane}; +use fidl::endpoints; +use fidl_fuchsia_hardware_display::{ + ControllerEvent, ControllerMarker, ControllerProxy, ImageConfig, ImagePlane, + ProviderSynchronousProxy, +}; use fuchsia_async as fasync; use fuchsia_runtime::vmar_root_self; use fuchsia_zircon::{ self as zx, sys::{ - zx_cache_flush, zx_cache_policy_t::ZX_CACHE_POLICY_WRITE_COMBINING, zx_handle_t, + zx_cache_flush, zx_cache_policy_t::ZX_CACHE_POLICY_WRITE_COMBINING, ZX_CACHE_FLUSH_DATA, ZX_TIME_INFINITE, }, - Handle, VmarFlags, Vmo, + VmarFlags, Vmo, }; use futures::{future, StreamExt, TryFutureExt, TryStreamExt}; use shared_buffer::SharedBuffer; use std::cell::RefCell; -use std::fs::{File, OpenOptions}; -use std::mem; -use std::os::unix::io::AsRawFd; -use std::ptr; +use std::fs::OpenOptions; use std::rc::Rc; use std::{thread, time}; @@ -295,38 +294,13 @@ impl Drop for Frame { } pub struct FrameBuffer { - display_controller: File, + display_controller: zx::Channel, controller: ControllerProxy, config: Config, layer_id: u64, } impl FrameBuffer { - fn get_display_handle(file: &File) -> Result<Handle, Error> { - let fd = file.as_raw_fd() as i32; - let ioctl_display_controller_get_handle = - make_ioctl(IOCTL_KIND_GET_HANDLE, IOCTL_FAMILY_DISPLAY_CONTROLLER, 1); - let mut display_handle: zx_handle_t = 0; - let display_handle_ptr: *mut std::os::raw::c_void = - &mut display_handle as *mut _ as *mut std::os::raw::c_void; - let result_size = unsafe { - fdio_ioctl( - fd, - ioctl_display_controller_get_handle, - ptr::null(), - 0, - display_handle_ptr, - mem::size_of::<zx_handle_t>(), - ) - }; - - if result_size != mem::size_of::<zx_handle_t>() as isize { - return Err(format_err!("ioctl_display_controller_get_handle failed: {}", result_size)); - } - - Ok(unsafe { Handle::from_raw(display_handle) }) - } - fn create_config_from_event_stream( proxy: &ControllerProxy, executor: &mut fasync::Executor, @@ -445,14 +419,23 @@ impl FrameBuffer { first_path.unwrap() }; let file = OpenOptions::new().read(true).write(true).open(device_path)?; - let zx_handle = Self::get_display_handle(&file)?; - let channel = fasync::Channel::from_channel(zx_handle.into())?; - let proxy = ControllerProxy::new(channel); + + let channel = fdio::clone_channel(&file)?; + let mut provider = ProviderSynchronousProxy::new(channel); + + let (device_client, device_server) = zx::Channel::create()?; + let (dc_client, dc_server) = endpoints::create_endpoints::<ControllerMarker>()?; + let status = provider.open_controller(device_server, dc_server, zx::Time::INFINITE)?; + if status != zx::sys::ZX_OK { + return Err(format_err!("Failed to open display controller")); + } + + let proxy = dc_client.into_proxy()?; let config = Self::create_config_from_event_stream(&proxy, executor)?; let layer = Self::configure_layer(config, &proxy, executor)?; Ok(FrameBuffer { - display_controller: file, + display_controller: device_client, controller: proxy, config: config, layer_id: layer, diff --git a/garnet/tests/gfxlatency/main.cpp b/garnet/tests/gfxlatency/main.cpp index 8f364a35d0748aff08050574b761789265c57bef..d78aa0878415c8cd08ea04316ef3a7481b813c7c 100644 --- a/garnet/tests/gfxlatency/main.cpp +++ b/garnet/tests/gfxlatency/main.cpp @@ -34,6 +34,7 @@ #include <zircon/process.h> #include <zircon/syscalls.h> #include <zircon/types.h> +#include <zircon/status.h> #include <utility> @@ -814,19 +815,38 @@ int main(int argc, char* argv[]) { } } - int32_t dc_fd = open("/dev/class/display-controller/000", O_RDWR); - if (dc_fd < 0) { + fbl::unique_fd fd(open("/dev/class/display-controller/000", O_RDWR)); + if (!fd) { fprintf(stderr, "failed to open display controller\n"); return -1; } - if (ioctl_display_controller_get_handle(dc_fd, &dc_handle) != - sizeof(zx_handle_t)) { - fprintf(stderr, "failed to get display controller handle\n"); + zx::channel device_server, device_client; + zx_status_t status = zx::channel::create(0, &device_server, &device_client); + if (status != ZX_OK) { + fprintf(stderr, "failed to create device channel %d (%s)\n", status, zx_status_get_string(status)); + return -1; + } + zx::channel dc_server, dc_client; + status = zx::channel::create(0, &dc_server, &dc_client); + if (status != ZX_OK) { + fprintf(stderr, "failed to create controller channel %d (%s)\n", status, zx_status_get_string(status)); return -1; } - zx_status_t status; + fzl::FdioCaller caller(std::move(fd)); + zx_status_t fidl_status = fuchsia_hardware_display_ProviderOpenController( + caller.borrow_channel(), device_server.release(), dc_server.release(), &status); + if (fidl_status != ZX_OK) { + fprintf(stderr, "failed to call service handle %d (%s)\n", fidl_status, zx_status_get_string(fidl_status)); + return -1; + } + if (status != ZX_OK) { + fprintf(stderr, "failed to open controller %d (%s)\n", status, zx_status_get_string(status)); + return -1; + } + dc_handle = dc_client.release(); + uint8_t bytes[ZX_CHANNEL_MAX_MSG_BYTES]; uint32_t actual_bytes, actual_handles; bool has_display = false; @@ -1998,6 +2018,5 @@ int main(int argc, char* argv[]) { if (touchpadfd >= 0) close(touchpadfd); zx_handle_close(dc_handle); - close(dc_fd); return 0; } diff --git a/zircon/system/core/virtcon/vc-display.cpp b/zircon/system/core/virtcon/vc-display.cpp index 0212e9c72ee2310713ed992ddaab4c30541e3363..71986ad51de9ef7f881b198befb5501357bd30c1 100644 --- a/zircon/system/core/virtcon/vc-display.cpp +++ b/zircon/system/core/virtcon/vc-display.cpp @@ -5,6 +5,7 @@ #include <fbl/unique_fd.h> #include <fcntl.h> #include <fuchsia/io/c/fidl.h> +#include <lib/fdio/fd.h> #include <lib/fdio/io.h> #include <lib/fidl/coding.h> #include <lib/fzl/fdio.h> @@ -25,7 +26,7 @@ static constexpr const char* kDisplayControllerDir = "/dev/class/display-controller"; static int dc_dir_fd; -static int dc_fd; +static zx_handle_t dc_device; // At any point, |dc_ph| will either be waiting on the display controller device directory // for a display controller instance or it will be waiting on a display controller interface @@ -568,7 +569,7 @@ static zx_status_t dc_callback_handler(port_handler_t* ph, zx_signals_t signals, handle_display_removed(list_peek_head_type(&display_list, display_info_t, node)->id); } - close(dc_fd); + zx_handle_close(dc_device); zx_handle_close(dc_ph.handle); vc_find_display_controller(); @@ -618,30 +619,45 @@ static zx_status_t vc_dc_event(uint32_t evt, const char* name) { return ZX_OK; } - printf("vc: new display device %s/%s/virtcon\n", kDisplayControllerDir, name); + printf("vc: new display device %s/%s\n", kDisplayControllerDir, name); char buf[64]; - snprintf(buf, 64, "%s/%s/virtcon", kDisplayControllerDir, name); + snprintf(buf, 64, "%s/%s", kDisplayControllerDir, name); fbl::unique_fd fd(open(buf, O_RDWR)); if (!fd) { printf("vc: failed to open display controller device\n"); return ZX_OK; } - zx::channel dc_channel; - if (ioctl_display_controller_get_handle(fd.get(), dc_channel.reset_and_get_address()) - != sizeof(zx_handle_t)) { - printf("vc: failed to get display controller handle\n"); - return ZX_OK; + zx::channel device_server, device_client; + zx_status_t status = zx::channel::create(0, &device_server, &device_client); + if (status != ZX_OK) { + return status; + } + + zx::channel dc_server, dc_client; + status = zx::channel::create(0, &dc_server, &dc_client); + if (status != ZX_OK) { + return status; + } + + fzl::FdioCaller caller(std::move(fd)); + zx_status_t fidl_status = fuchsia_hardware_display_ProviderOpenVirtconController( + caller.borrow_channel(), device_server.release(), dc_server.release(), &status); + if (fidl_status != ZX_OK) { + return fidl_status; + } + if (status != ZX_OK) { + return status; } + dc_device = device_client.release(); zx_handle_close(dc_ph.handle); - dc_fd = fd.release(); - dc_ph.handle = dc_channel.release(); + dc_ph.handle = dc_client.release(); - zx_status_t status = vc_set_mode(getenv("virtcon.hide-on-boot") == nullptr - ? fuchsia_hardware_display_VirtconMode_FALLBACK - : fuchsia_hardware_display_VirtconMode_INACTIVE); + status = vc_set_mode(getenv("virtcon.hide-on-boot") == nullptr + ? fuchsia_hardware_display_VirtconMode_FALLBACK + : fuchsia_hardware_display_VirtconMode_INACTIVE); if (status != ZX_OK) { printf("vc: Failed to set initial ownership %d\n", status); vc_find_display_controller(); diff --git a/zircon/system/dev/display/display/BUILD.gn b/zircon/system/dev/display/display/BUILD.gn index 962fa9ecd469c302fb3e930ac267aff7b578a78d..5417b8a7b02b0e4e80b87bb76d2235c4c6e8d5eb 100644 --- a/zircon/system/dev/display/display/BUILD.gn +++ b/zircon/system/dev/display/display/BUILD.gn @@ -23,6 +23,7 @@ driver("display") { "$zx/system/ulib/edid", "$zx/system/ulib/fbl", "$zx/system/ulib/fidl", + "$zx/system/ulib/fidl-utils", "$zx/system/ulib/hwreg", "$zx/system/ulib/image-format", "$zx/system/ulib/trace:trace-driver", diff --git a/zircon/system/dev/display/display/client.cpp b/zircon/system/dev/display/display/client.cpp index 19fef600bce89f3c84bec6b797a25b5f188092a5..75759f7f29b93cb6e77f44ac770468d4c094795e 100644 --- a/zircon/system/dev/display/display/client.cpp +++ b/zircon/system/dev/display/display/client.cpp @@ -1864,7 +1864,7 @@ void ClientProxy::OnDisplayVsync(uint64_t display_id, zx_time_t timestamp, memcpy(msg + 1, image_ids, sizeof(uint64_t) * count); - zx_status_t status = server_handle_.write(0, data, size, nullptr, 0); + zx_status_t status = server_channel_.write(0, data, size, nullptr, 0); if (status != ZX_OK) { zxlogf(WARN, "Failed to send vsync event %d\n", status); } @@ -1874,7 +1874,7 @@ void ClientProxy::OnClientDead() { controller_->OnClientDead(this); // After OnClientDead, there won't be any more vsync calls. Since that is the only use of // the channel off of the loop thread, there's no need to worry about synchronization. - server_handle_.reset(); + server_channel_.reset(); } void ClientProxy::Close() { @@ -1916,28 +1916,8 @@ void ClientProxy::Close() { } } -zx_status_t ClientProxy::DdkIoctl(uint32_t op, const void* in_buf, size_t in_len, void* out_buf, - size_t out_len, size_t* actual) { - switch (op) { - case IOCTL_DISPLAY_CONTROLLER_GET_HANDLE: { - if (out_len != sizeof(zx_handle_t)) { - return ZX_ERR_INVALID_ARGS; - } - - if (client_handle_.get() == ZX_HANDLE_INVALID) { - return ZX_ERR_ALREADY_BOUND; - } - - *reinterpret_cast<zx_handle_t*>(out_buf) = client_handle_.release(); - *actual = sizeof(zx_handle_t); - return ZX_OK; - } - default: - return ZX_ERR_NOT_SUPPORTED; - } -} - zx_status_t ClientProxy::DdkClose(uint32_t flags) { + printf("DdkClose\n"); Close(); return ZX_OK; } @@ -1946,15 +1926,9 @@ void ClientProxy::DdkRelease() { delete this; } -zx_status_t ClientProxy::Init() { - zx_status_t status; - if ((status = zx_channel_create(0, server_handle_.reset_and_get_address(), - client_handle_.reset_and_get_address())) != ZX_OK) { - zxlogf(ERROR, "Failed to create channels %d\n", status); - return status; - } - - return handler_.Init(server_handle_.get()); +zx_status_t ClientProxy::Init(zx::channel server_channel) { + server_channel_ = std::move(server_channel); + return handler_.Init(server_channel_.get()); } ClientProxy::ClientProxy(Controller* controller, bool is_vc) diff --git a/zircon/system/dev/display/display/client.h b/zircon/system/dev/display/display/client.h index 27da3e2e0a776504b48e58b9549820ea3ee41825..68fae4de38faeb6307997ec90e8b4f55819f5940 100644 --- a/zircon/system/dev/display/display/client.h +++ b/zircon/system/dev/display/display/client.h @@ -268,16 +268,14 @@ private: // ClientProxy manages interactions between its Client instance and the ddk and the // controller. Methods on this class are thread safe. -using ClientParent = ddk::Device<ClientProxy, ddk::Ioctlable, ddk::Closable>; +using ClientParent = ddk::Device<ClientProxy, ddk::Closable>; class ClientProxy : public ClientParent { public: ClientProxy(Controller* controller, bool is_vc); ~ClientProxy(); - zx_status_t Init(); + zx_status_t Init(zx::channel server_channel); zx_status_t DdkClose(uint32_t flags); - zx_status_t DdkIoctl(uint32_t op, const void* in_buf, size_t in_len, - void* out_buf, size_t out_len, size_t* actual); void DdkRelease(); // Requires holding controller_->mtx() lock @@ -302,8 +300,7 @@ private: Client handler_; bool enable_vsync_ = false; - zx::channel server_handle_; - zx::channel client_handle_; + zx::channel server_channel_; }; } // namespace display diff --git a/zircon/system/dev/display/display/controller.cpp b/zircon/system/dev/display/display/controller.cpp index 26764517daafe7fbc7bce085f4ab47c8725cbf97..257b20dfb0d739a74dcce7e46a1f72140125296c 100644 --- a/zircon/system/dev/display/display/controller.cpp +++ b/zircon/system/dev/display/display/controller.cpp @@ -752,10 +752,11 @@ bool Controller::GetDisplayIdentifiers(uint64_t display_id, const char** manufac } zx_status_t Controller::DdkOpen(zx_device_t** dev_out, uint32_t flags) { - return DdkOpenAt(dev_out, "", flags); + return ZX_OK; } -zx_status_t Controller::DdkOpenAt(zx_device_t** dev_out, const char* path, uint32_t flags) { +zx_status_t Controller::CreateClient(bool is_vc, zx::channel device_channel, + zx::channel client_channel) { fbl::AllocChecker ac; fbl::unique_ptr<async::Task> task = fbl::make_unique_checked<async::Task>(&ac); if (!ac.check()) { @@ -765,7 +766,6 @@ zx_status_t Controller::DdkOpenAt(zx_device_t** dev_out, const char* path, uint3 fbl::AutoLock lock(&mtx_); - bool is_vc = strcmp("virtcon", path) == 0; if ((is_vc && vc_client_) || (!is_vc && primary_client_)) { zxlogf(TRACE, "Already bound\n"); return ZX_ERR_ALREADY_BOUND; @@ -777,21 +777,27 @@ zx_status_t Controller::DdkOpenAt(zx_device_t** dev_out, const char* path, uint3 return ZX_ERR_NO_MEMORY; } - zx_status_t status = client->Init(); + zx_status_t status = client->Init(std::move(client_channel)); if (status != ZX_OK) { zxlogf(TRACE, "Failed to init client %d\n", status); return status; } - if ((status = client->DdkAdd(is_vc ? "dc-vc" : "dc", DEVICE_ADD_INSTANCE)) != ZX_OK) { + status = client->DdkAdd(is_vc ? "dc-vc" : "dc", + DEVICE_ADD_INSTANCE, + nullptr /* props */, + 0 /* prop_count */, + 0 /* proto_id */, + nullptr /* proxy_args */, + device_channel.release()); + if (status != ZX_OK) { zxlogf(TRACE, "Failed to add client %d\n", status); return status; } ClientProxy* client_ptr = client.release(); - *dev_out = client_ptr->zxdev(); - zxlogf(TRACE, "New client connected at \"%s\"\n", path); + zxlogf(TRACE, "New client connected.\n"); if (is_vc) { vc_client_ = client_ptr; @@ -831,6 +837,28 @@ zx_status_t Controller::DdkOpenAt(zx_device_t** dev_out, const char* path, uint3 return task.release()->Post(loop_.dispatcher()); } +zx_status_t Controller::OpenVirtconController(zx_handle_t device, zx_handle_t controller, + fidl_txn_t* txn) { + zx::channel device_channel(device); + zx::channel controller_channel(controller); + zx_status_t status = CreateClient(true /* is_vc */, std::move(device_channel), + std::move(controller_channel)); + return fuchsia_hardware_display_ProviderOpenVirtconController_reply(txn, status); +} + +zx_status_t Controller::OpenController(zx_handle_t device, zx_handle_t controller, + fidl_txn_t* txn) { + zx::channel device_channel(device); + zx::channel controller_channel(controller); + zx_status_t status = CreateClient(false /* is_vc */, std::move(device_channel), + std::move(controller_channel)); + return fuchsia_hardware_display_ProviderOpenController_reply(txn, status); +} + +zx_status_t Controller::DdkMessage(fidl_msg_t* msg, fidl_txn_t* txn) { + return fuchsia_hardware_display_Provider_dispatch(this, txn, msg, &fidl_ops_); +} + zx_status_t Controller::Bind(fbl::unique_ptr<display::Controller>* device_ptr) { zx_status_t status; dc_ = ddk::DisplayControllerImplProtocolClient(parent_); diff --git a/zircon/system/dev/display/display/controller.h b/zircon/system/dev/display/display/controller.h index cd560d8dff81e7113b2e79e3b53691189e9f8065..95be81927e8a2263219edf06dfb91698d5b1303b 100644 --- a/zircon/system/dev/display/display/controller.h +++ b/zircon/system/dev/display/display/controller.h @@ -11,6 +11,7 @@ #include <ddktl/protocol/empty-protocol.h> #include <ddktl/protocol/i2cimpl.h> #include <fbl/array.h> +#include <lib/fidl-utils/bind.h> #include <fbl/intrusive_double_list.h> #include <fbl/intrusive_hash_table.h> #include <fbl/unique_ptr.h> @@ -65,7 +66,7 @@ public: bool switching_client = false; }; -using ControllerParent = ddk::Device<Controller, ddk::Unbindable, ddk::Openable, ddk::OpenAtable>; +using ControllerParent = ddk::Device<Controller, ddk::Unbindable, ddk::Openable, ddk::Messageable>; class Controller : public ControllerParent, public ddk::DisplayControllerInterfaceProtocol<Controller>, public ddk::EmptyProtocol<ZX_PROTOCOL_DISPLAY_CONTROLLER> { @@ -75,7 +76,7 @@ public: static void PopulateDisplayMode(const edid::timing_params_t& params, display_mode_t* mode); zx_status_t DdkOpen(zx_device_t** dev_out, uint32_t flags); - zx_status_t DdkOpenAt(zx_device_t** dev_out, const char* path, uint32_t flags); + zx_status_t DdkMessage(fidl_msg_t* msg, fidl_txn_t* txn); void DdkUnbind(); void DdkRelease(); zx_status_t Bind(fbl::unique_ptr<display::Controller>* device_ptr); @@ -124,6 +125,16 @@ private: void HandleClientOwnershipChanges() __TA_REQUIRES(mtx_); void PopulateDisplayTimings(const fbl::RefPtr<DisplayInfo>& info) __TA_EXCLUDES(mtx_); void PopulateDisplayAudio(const fbl::RefPtr<DisplayInfo>& info); + zx_status_t CreateClient(bool is_vc, zx::channel device, zx::channel client); + + zx_status_t OpenVirtconController(zx_handle_t device, zx_handle_t controller, fidl_txn_t* txn); + zx_status_t OpenController(zx_handle_t device, zx_handle_t controller, fidl_txn_t* txn); + + static constexpr fuchsia_hardware_display_Provider_ops_t fidl_ops_ = { + .OpenVirtconController = + fidl::Binder<Controller>::BindMember<&Controller::OpenVirtconController>, + .OpenController = fidl::Binder<Controller>::BindMember<&Controller::OpenController>, + }; // mtx_ is a global lock on state shared among clients. mtx_t mtx_; diff --git a/zircon/system/fidl/fuchsia-hardware-display/display-controller.fidl b/zircon/system/fidl/fuchsia-hardware-display/display-controller.fidl index bb146a71eff959f74319cc5fbbee542deaab1340..003ed330e51099e62fe0da52ef1bbb8fd6b18c51 100644 --- a/zircon/system/fidl/fuchsia-hardware-display/display-controller.fidl +++ b/zircon/system/fidl/fuchsia-hardware-display/display-controller.fidl @@ -171,26 +171,49 @@ struct ClientCompositionOp { ClientCompositionOpcode opcode; }; -// Interface for accessing the display hardware. -// -// The driver supports two simultaneous clients - a primary client and a virtcon -// client. The primary client is obtained by directly opening the devfs device, -// while the virtcon client is obtained by opening a 'virtcon' child of the -// device. -// -// A display configuration can be separated into two parts: the layer layout and -// the layer contents. The layout includes all parts of a configuration other -// than the image handles. The active configuration is composed of the most -// recently applied layout and an active image from each layer - see -// SetLayerImage for details on how the active image is defined. Note the -// requirement that each layer has an active image. Whenever a new active -// configuration is available, it is immediately given to the hardware. This -// allows the layout and each layer's contents to advance independently when -// possible. -// - -// Performing illegal actions on the interface will result in the interface -// being closed. +/// Provider for display controllers. +/// +/// The driver supports two simultaneous clients - a primary client and a virtcon +/// client. +[Layout = "Simple"] +protocol Provider { + /// Open a virtcon client. |device| should be a handle to one endpoint of a + /// channel that (on success) will become an open connection to a new + /// instance of a display client device. An protocol request |controller| + /// provides an interface to the Controller for the new device. Closing the + /// connection to |device| will also close the |controller| interface. If + /// the display device already has a virtcon controller then this method + /// will return ZX_ERR_ALREADY_BOUND. + // TODO(ZX-3889): Once llcpp is supported in Zircon, unify |device| and + // |controller|. + OpenVirtconController(handle<channel> device, request<Controller> controller) -> (zx.status s); + + /// Open a primary client. |device| should be a handle to one endpoint of a + /// channel that (on success) will become an open connection to a new + /// instance of a display client device. An protocol request |controller| + /// provides an interface to the Controller for the new device. Closing the + /// connection to |device| will also close the |controller| interface. If + /// the display device already has a primary controller then this method + /// will return ZX_ERR_ALREADY_BOUND. + // TODO(ZX-3889): Once llcpp is supported in Zircon, unify |device| and + // |controller|. + OpenController(handle<channel> device, request<Controller> controller) -> (zx.status s); +}; + +/// Interface for accessing the display hardware. +/// +/// A display configuration can be separated into two parts: the layer layout and +/// the layer contents. The layout includes all parts of a configuration other +/// than the image handles. The active configuration is composed of the most +/// recently applied layout and an active image from each layer - see +/// SetLayerImage for details on how the active image is defined. Note the +/// requirement that each layer has an active image. Whenever a new active +/// configuration is available, it is immediately given to the hardware. This +/// allows the layout and each layer's contents to advance independently when +/// possible. +/// +/// Performing illegal actions on the interface will result in the interface +/// being closed. protocol Controller { // Event fired when displays are added or removed. This event will be fired // when the callback is registered if there are any connected displays. diff --git a/zircon/system/uapp/display-test/BUILD.gn b/zircon/system/uapp/display-test/BUILD.gn index 56791cde207f309cbd653754e9c9fd547d8cfb45..48e0294a5e6298953006e8824962a94169d2f9ea 100644 --- a/zircon/system/uapp/display-test/BUILD.gn +++ b/zircon/system/uapp/display-test/BUILD.gn @@ -15,6 +15,7 @@ executable("display-test") { "$zx/system/ulib/fbl", "$zx/system/ulib/fdio", "$zx/system/ulib/fidl", + "$zx/system/ulib/fzl", "$zx/system/ulib/zircon", "$zx/system/ulib/zx", "$zx/system/ulib/zxcpp", diff --git a/zircon/system/uapp/display-test/main.cpp b/zircon/system/uapp/display-test/main.cpp index 8b5c3e4c7d94281418595630765a4ee37c3e812a..d53ddcc4e782a615466af1248bb1e03fa9b4aa21 100644 --- a/zircon/system/uapp/display-test/main.cpp +++ b/zircon/system/uapp/display-test/main.cpp @@ -14,11 +14,13 @@ #include <zircon/syscalls.h> #include <zircon/types.h> -#include <fbl/vector.h> #include <fbl/algorithm.h> +#include <fbl/vector.h> +#include <fbl/unique_fd.h> #include <lib/fidl/cpp/message.h> #include <lib/fidl/cpp/string_view.h> #include <lib/fidl/cpp/vector_view.h> +#include <lib/fzl/fdio.h> #include <zircon/pixelformat.h> #include <zircon/status.h> @@ -28,6 +30,7 @@ #include "fuchsia/hardware/display/c/fidl.h" #include "virtual-layer.h" +static zx_handle_t device_handle; static zx_handle_t dc_handle; static bool has_ownership; @@ -47,17 +50,43 @@ static bool wait_for_driver_event(zx_time_t deadline) { static bool bind_display(fbl::Vector<Display>* displays) { printf("Opening controller\n"); - int vfd = open("/dev/class/display-controller/000", O_RDWR); - if (vfd < 0) { + fbl::unique_fd fd(open("/dev/class/display-controller/000", O_RDWR)); + if (!fd) { printf("Failed to open display controller (%d)\n", errno); return false; } - if (ioctl_display_controller_get_handle(vfd, &dc_handle) != sizeof(zx_handle_t)) { - printf("Failed to get display controller handle\n"); + zx::channel device_server, device_client; + zx_status_t status = zx::channel::create(0, &device_server, &device_client); + if (status != ZX_OK) { + printf("Failed to create device channel %d (%s)\n", status, zx_status_get_string(status)); + return false; + } + + zx::channel dc_server, dc_client; + status = zx::channel::create(0, &dc_server, &dc_client); + if (status != ZX_OK) { + printf("Failed to create controller channel %d (%s)\n", status, + zx_status_get_string(status)); + return false; + } + + fzl::FdioCaller caller(std::move(fd)); + zx_status_t fidl_status = fuchsia_hardware_display_ProviderOpenController( + caller.borrow_channel(), device_server.release(), dc_server.release(), &status); + if (fidl_status != ZX_OK) { + printf("Failed to call service handle %d (%s)\n", fidl_status, + zx_status_get_string(fidl_status)); + return false; + } + if (status != ZX_OK) { + printf("Failed to open controller %d (%s)\n", status, zx_status_get_string(status)); return false; } + dc_handle = dc_client.release(); + device_handle = device_client.release(); + uint8_t byte_buffer[ZX_CHANNEL_MAX_MSG_BYTES]; fidl::Message msg(fidl::BytePart(byte_buffer, ZX_CHANNEL_MAX_MSG_BYTES), fidl::HandlePart()); while (displays->is_empty()) { @@ -512,5 +541,8 @@ int main(int argc, const char* argv[]) { printf("Done rendering\n"); zx_nanosleep(zx_deadline_after(ZX_MSEC(500))); + zx_handle_close(dc_handle); + zx_handle_close(device_handle); + return 0; } diff --git a/zircon/system/ulib/framebuffer/BUILD.gn b/zircon/system/ulib/framebuffer/BUILD.gn index 8c7884636c81f30f2d140d2831406ed498c45050..923430c74b902235dbd0f2d3fd11fe7f756586b8 100644 --- a/zircon/system/ulib/framebuffer/BUILD.gn +++ b/zircon/system/ulib/framebuffer/BUILD.gn @@ -14,6 +14,7 @@ library("framebuffer") { "$zx/system/ulib/fbl", "$zx/system/ulib/fdio", "$zx/system/ulib/fidl", + "$zx/system/ulib/fzl", "$zx/system/ulib/zircon", "$zx/system/ulib/zx", ] diff --git a/zircon/system/ulib/framebuffer/framebuffer.cpp b/zircon/system/ulib/framebuffer/framebuffer.cpp index 5d557a7b476cbcfb363dcf7bcfc67807227d978b..486f3028186ca99a851f0d3c52205697f5b9127b 100644 --- a/zircon/system/ulib/framebuffer/framebuffer.cpp +++ b/zircon/system/ulib/framebuffer/framebuffer.cpp @@ -10,7 +10,9 @@ #include <unistd.h> #include <fbl/auto_call.h> +#include <fbl/unique_fd.h> #include <lib/fidl/coding.h> +#include <lib/fzl/fdio.h> #include <lib/zx/vmo.h> #include <zircon/assert.h> #include <zircon/device/display-controller.h> @@ -22,7 +24,7 @@ #include "fuchsia/hardware/display/c/fidl.h" #include "lib/framebuffer/framebuffer.h" -static int32_t dc_fd = -1; +static zx_handle_t device_handle = ZX_HANDLE_INVALID; static zx_handle_t dc_handle = ZX_HANDLE_INVALID; static int32_t txid; @@ -84,23 +86,44 @@ zx_status_t fb_bind(bool single_buffer, const char** err_msg_out) { } // TODO(stevensd): Don't hardcode display controller 0 - zx_status_t status; - dc_fd = open("/dev/class/display-controller/000", O_RDWR); - if (dc_fd < 0) { + fbl::unique_fd dc_fd(open("/dev/class/display-controller/000", O_RDWR)); + if (!dc_fd) { *err_msg_out = "Failed to open display controller"; return ZX_ERR_NO_RESOURCES; } - fbl::AutoCall close_dc_fd([]() { - close(dc_fd); - dc_fd = -1; - }); - if (ioctl_display_controller_get_handle(dc_fd, &dc_handle) != sizeof(zx_handle_t)) { - *err_msg_out = "Failed to get display controller handle"; - return ZX_ERR_INTERNAL; + zx::channel device_server, device_client; + zx_status_t status = zx::channel::create(0, &device_server, &device_client); + if (status != ZX_OK) { + *err_msg_out = "Failed to create device channel"; + return status; + } + + zx::channel dc_server, dc_client; + status = zx::channel::create(0, &dc_server, &dc_client); + if (status != ZX_OK) { + *err_msg_out = "Failed to create controller channel"; + return status; } + + fzl::FdioCaller caller(std::move(dc_fd)); + zx_status_t fidl_status = fuchsia_hardware_display_ProviderOpenController( + caller.borrow_channel(), device_server.release(), dc_server.release(), &status); + if (fidl_status != ZX_OK) { + *err_msg_out = "Failed to call service handle"; + return fidl_status; + } + if (status != ZX_OK) { + *err_msg_out = "Failed to open controller"; + return status; + } + + device_handle = device_client.release(); + dc_handle = dc_client.release(); fbl::AutoCall close_dc_handle([]() { + zx_handle_close(device_handle); zx_handle_close(dc_handle); + device_handle = ZX_HANDLE_INVALID; dc_handle = ZX_HANDLE_INVALID; }); @@ -283,7 +306,6 @@ zx_status_t fb_bind(bool single_buffer, const char** err_msg_out) { clear_inited.cancel(); vmo = local_vmo.release(); - close_dc_fd.cancel(); close_dc_handle.cancel(); return ZX_OK; @@ -294,12 +316,11 @@ void fb_release() { return; } + zx_handle_close(device_handle); zx_handle_close(dc_handle); + device_handle = ZX_HANDLE_INVALID; dc_handle = ZX_HANDLE_INVALID; - close(dc_fd); - dc_fd = -1; - if (in_single_buffer_mode) { zx_handle_close(vmo); vmo = ZX_HANDLE_INVALID;