blob: 55bce96f51e6f9fc43ce28dc8866fbc0e025f621 [file] [log] [blame]
// 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.
#pragma once
#include <ddktl/device.h>
#include <ddk/protocol/display-controller.h>
#include <fbl/atomic.h>
#include <fbl/intrusive_double_list.h>
#include <fbl/intrusive_hash_table.h>
#include <fbl/unique_ptr.h>
#include <fbl/vector.h>
#include <lib/async/cpp/receiver.h>
#include <lib/async/cpp/task.h>
#include <lib/async/cpp/wait.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/fidl/cpp/builder.h>
#include <lib/zx/channel.h>
#include <lib/zx/event.h>
#include <zircon/device/display-controller.h>
#include <zircon/listnode.h>
#include "controller.h"
#include "fence.h"
#include "fuchsia/display/c/fidl.h"
#include "id-map.h"
#include "image.h"
namespace display {
class Layer;
class Client;
typedef struct layer_node : public fbl::SinglyLinkedListable<layer_node*> {
Layer* layer;
} layer_node_t;
// Almost-POD used by Client to manage layer state. Public state is used by Controller.
class Layer : public IdMappable<fbl::unique_ptr<Layer>> {
public:
fbl::RefPtr<Image> current_image() const { return displayed_image_; };
uint32_t z_order() const { return current_layer_.z_index; }
private:
layer_t pending_layer_;
layer_t current_layer_;
// flag indicating that there are changes in pending_layer that
// need to be applied to current_layer.
bool config_change_;
// Event ids passed to SetLayerImage which haven't been applied yet.
uint64_t pending_wait_event_id_;
uint64_t pending_present_event_id_;
uint64_t pending_signal_event_id_;
// The image given to SetLayerImage which hasn't been applied yet.
fbl::RefPtr<Image> pending_image_;
// Image which are waiting to be displayed
fbl::DoublyLinkedList<fbl::RefPtr<Image>> waiting_images_;
// The image which has most recently been sent to the display controller impl
fbl::RefPtr<Image> displayed_image_;
layer_node_t pending_node_;
layer_node_t current_node_;
// The display this layer was most recently displayed on
uint64_t current_display_id_;
friend Client;
};
// Almost-POD used by Client to manage display configuration. Public state is used by Controller.
class DisplayConfig : public IdMappable<fbl::unique_ptr<DisplayConfig>> {
public:
bool apply_layer_change() {
bool ret = pending_apply_layer_change_;
pending_apply_layer_change_ = false;
return ret;
}
uint32_t current_layer_count() const { return current_.layer_count; }
const display_config_t* current_config() const { return &current_; }
const fbl::SinglyLinkedList<layer_node_t*>& get_current_layers() const {
return current_layers_;
}
private:
display_config_t current_;
display_config_t pending_;
bool pending_layer_change_;
bool pending_apply_layer_change_;
fbl::SinglyLinkedList<layer_node_t*> pending_layers_;
fbl::SinglyLinkedList<layer_node_t*> current_layers_;
fbl::unique_ptr<zx_pixel_format_t[]> pixel_formats_;
uint32_t pixel_format_count_;
friend Client;
friend ClientProxy;
};
// The Client class manages all state associated with an open display client
// connection. Over than initialization, all methods of this class execute on
// on the controller's looper, so no synchronization is necessary.
class Client : private FenceCallback {
public:
Client(Controller* controller, ClientProxy* proxy, bool is_vc);
~Client();
zx_status_t Init(zx::channel* client_handle);
void OnDisplaysChanged(fbl::unique_ptr<DisplayConfig>* displays_added,
uint32_t added_count,
uint64_t* displays_removed,
uint32_t removed_count);
void SetOwnership(bool is_owner);
void ApplyConfig();
void OnFenceFired(FenceReference* fence) override;
void OnRefForFenceDead(Fence* fence) override;
void TearDown();
bool IsValid() { return server_handle_.get() != ZX_HANDLE_INVALID; }
private:
void HandleImportVmoImage(const fuchsia_display_ControllerImportVmoImageRequest* req,
fidl::Builder* resp_builder, const fidl_type_t** resp_table);
void HandleReleaseImage(const fuchsia_display_ControllerReleaseImageRequest* req,
fidl::Builder* resp_builder, const fidl_type_t** resp_table);
void HandleImportEvent(const fuchsia_display_ControllerImportEventRequest* req,
fidl::Builder* resp_builder, const fidl_type_t** resp_table);
void HandleReleaseEvent(const fuchsia_display_ControllerReleaseEventRequest* req,
fidl::Builder* resp_builder, const fidl_type_t** resp_table);
void HandleSetDisplayImage(const fuchsia_display_ControllerSetDisplayImageRequest* req,
fidl::Builder* resp_builder, const fidl_type_t** resp_table);
void HandleCreateLayer(const fuchsia_display_ControllerCreateLayerRequest* req,
fidl::Builder* resp_builder, const fidl_type_t** resp_table);
void HandleDestroyLayer(const fuchsia_display_ControllerDestroyLayerRequest* req,
fidl::Builder* resp_builder, const fidl_type_t** resp_table);
void HandleSetDisplayLayers(const fuchsia_display_ControllerSetDisplayLayersRequest* req,
fidl::Builder* resp_builder, const fidl_type_t** resp_table);
void HandleSetLayerPrimaryConfig(
const fuchsia_display_ControllerSetLayerPrimaryConfigRequest* req,
fidl::Builder* resp_builder, const fidl_type_t** resp_table);
void HandleSetLayerPrimaryPosition(
const fuchsia_display_ControllerSetLayerPrimaryPositionRequest* req,
fidl::Builder* resp_builder, const fidl_type_t** resp_table);
void HandleSetLayerImage(const fuchsia_display_ControllerSetLayerImageRequest* req,
fidl::Builder* resp_builder, const fidl_type_t** resp_table);
void HandleCheckConfig(const fuchsia_display_ControllerCheckConfigRequest* req,
fidl::Builder* resp_builder, const fidl_type_t** resp_table);
void HandleApplyConfig(const fuchsia_display_ControllerApplyConfigRequest* req,
fidl::Builder* resp_builder, const fidl_type_t** resp_table);
void HandleSetOwnership(const fuchsia_display_ControllerSetOwnershipRequest* req,
fidl::Builder* resp_builder, const fidl_type_t** resp_table);
void HandleComputeLinearImageStride(
const fuchsia_display_ControllerComputeLinearImageStrideRequest* req,
fidl::Builder* resp_builder, const fidl_type_t** resp_table);
void HandleAllocateVmo(const fuchsia_display_ControllerAllocateVmoRequest* req,
fidl::Builder* resp_builder,
zx_handle_t* handle_out, bool* has_handle_out,
const fidl_type_t** resp_table);
zx_status_t CreateLayer(uint64_t* layer_id);
// Cleans up layer state associated with image id. If id == INVALID_ID, then
// cleans up all image layer state. Return true if a current layer was modified.
bool CleanUpImageLayerState(uint64_t id);
Controller* controller_;
ClientProxy* proxy_;
bool is_vc_;
uint64_t console_fb_display_id_ = -1;
zx::channel server_handle_;
uint64_t next_image_id_ = 1; // Only INVALID_ID == 0 is invalid
Image::Map images_;
DisplayConfig::Map configs_;
bool pending_config_valid_ = false;
bool is_owner_ = false;
// A counter for the number of times the client has successfully applied
// a configuration. This does not account for changes due to waiting images.
uint32_t client_apply_count_ = 0;
Fence::Map fences_ __TA_GUARDED(fence_mtx_);
// Mutex held when creating or destroying fences.
mtx_t fence_mtx_;
Layer::Map layers_;
uint64_t next_layer_id = 1;
// TODO(stevensd): Delete this when client stop using SetDisplayImage
uint64_t display_image_layer_ = INVALID_ID;
void HandleControllerApi(async_t* async, async::WaitBase* self,
zx_status_t status, const zx_packet_signal_t* signal);
async::WaitMethod<Client, &Client::HandleControllerApi> api_wait_{this};
void NotifyDisplaysChanged(const int32_t* displays_added, uint32_t added_count,
const int32_t* displays_removed, uint32_t removed_count);
bool CheckConfig(fidl::Builder* resp_builder);
fbl::RefPtr<FenceReference> GetFence(uint64_t id);
};
// 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>;
class ClientProxy : public ClientParent {
public:
ClientProxy(Controller* controller, bool is_vc);
~ClientProxy();
zx_status_t Init();
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();
zx_status_t OnDisplaysChanged(const DisplayInfo** displays_added, uint32_t added_count,
const uint64_t* displays_removed, uint32_t removed_count);
void SetOwnership(bool is_owner);
void ReapplyConfig();
void OnClientDead();
void Close();
private:
Controller* controller_;
bool is_vc_;
Client handler_;
zx::channel client_handle_;
};
} // namespace display