blob: c1d19ef772cbf85408c4d19ffc49ccbff4158989 [file] [log] [blame]
// Copyright 2021 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.
#ifndef SRC_GRAPHICS_BIN_VULKAN_LOADER_APP_H_
#define SRC_GRAPHICS_BIN_VULKAN_LOADER_APP_H_
#include <lib/async-loop/cpp/loop.h>
#include <lib/fit/defer.h>
#include <lib/fit/thread_checker.h>
#include <lib/sys/cpp/component_context.h>
#include <lib/sys/inspect/cpp/component.h>
#include <list>
#include <unordered_map>
#include "src/graphics/bin/vulkan_loader/gpu_device.h"
#include "src/lib/fsl/io/device_watcher.h"
#include "src/lib/fxl/macros.h"
#include "src/lib/fxl/observer_list.h"
#include "src/lib/storage/vfs/cpp/pseudo_dir.h"
#include "src/lib/storage/vfs/cpp/synchronous_vfs.h"
#include "src/lib/storage/vfs/cpp/vfs.h"
#include "src/lib/storage/vfs/cpp/vfs_types.h"
class MagmaDevice;
class IcdComponent;
class LoaderApp {
public:
class Observer {
public:
// Called if the ICD list may have changed.
virtual void OnIcdListChanged(LoaderApp* app) = 0;
};
// This token represents the existence of an outstanding operation that could
// affect the ICD list. It will defer the signaling that an ICD doesn't exist
// until it's destroyed.
class PendingActionToken {
public:
~PendingActionToken();
private:
friend class LoaderApp;
explicit PendingActionToken(LoaderApp* app) : app_(app) { app->pending_action_count_++; }
LoaderApp* app_;
FXL_DISALLOW_COPY_ASSIGN_AND_MOVE(PendingActionToken);
};
explicit LoaderApp(sys::ComponentContext* context, async_dispatcher_t* dispatcher);
~LoaderApp();
zx_status_t InitDeviceWatcher();
zx_status_t InitDeviceFs();
zx_status_t ServeDeviceFs(zx::channel dir_request);
std::shared_ptr<IcdComponent> CreateIcdComponent(std::string component_url);
void AddDevice(std::unique_ptr<GpuDevice> device) { devices_.push_back(std::move(device)); }
void RemoveDevice(GpuDevice* device);
// Notify observers that an ICD list has changed.
void NotifyIcdsChanged();
void AddObserver(Observer* obs) { observer_list_.AddObserver(obs); }
void RemoveObserver(Observer* obs) { observer_list_.RemoveObserver(obs); }
// Returns an ICD vmo that matches system_lib_name.
std::optional<zx::vmo> GetMatchingIcd(const std::string& system_lib_name);
size_t device_count() const { return devices_.size(); }
async_dispatcher_t* fdio_loop_dispatcher() { return fdio_loop_.dispatcher(); }
std::unique_ptr<PendingActionToken> GetPendingActionToken();
private:
friend class LoaderActionToken;
void NotifyIcdsChangedOnMainThread();
FIT_DECLARE_THREAD_CHECKER(main_thread_);
sys::ComponentContext* context_;
async_dispatcher_t* dispatcher_;
sys::ComponentInspector inspector_;
inspect::Node devices_node_;
inspect::Node icds_node_;
std::atomic_bool icd_notification_pending_{};
// Keep track of the number of pending operations that have to potential to modify the tree.
std::atomic<uint64_t> pending_action_count_{};
fs::SynchronousVfs device_fs_;
fbl::RefPtr<fs::PseudoDir> device_root_node_;
std::unique_ptr<fsl::DeviceWatcher> gpu_watcher_;
std::unique_ptr<fsl::DeviceWatcher> goldfish_watcher_;
std::vector<std::unique_ptr<GpuDevice>> devices_;
std::unordered_map<std::string, std::shared_ptr<IcdComponent>> icd_components_;
fxl::ObserverList<Observer> observer_list_;
// The FDIO loop is used to run FDIO commands that may access an ICD
// component's package. Those commands may block because they require the
// IcdRunner to service them.
async::Loop fdio_loop_;
};
#endif // SRC_GRAPHICS_BIN_VULKAN_LOADER_APP_H_