| // Copyright 2020 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 ZIRCON_PLATFORM_CONNECTION_H |
| #define ZIRCON_PLATFORM_CONNECTION_H |
| |
| #include <fidl/fuchsia.gpu.magma/cpp/wire.h> |
| #include <lib/async-loop/cpp/loop.h> |
| #include <lib/async/task.h> |
| #include <lib/async/time.h> |
| #include <lib/async/wait.h> |
| #include <lib/stdcompat/optional.h> |
| #include <lib/zx/channel.h> |
| #include <lib/zx/profile.h> |
| #include <zircon/status.h> |
| |
| #include "platform_connection.h" |
| #include "platform_handle.h" |
| #include "zircon_platform_event.h" |
| |
| namespace magma { |
| |
| static_assert(sizeof(msd_notification_t) == 4096, "msd_notification_t is not a page"); |
| |
| inline void CopyNotification(const msd_notification_t* src, msd_notification_t* dst) { |
| dst->type = src->type; |
| switch (dst->type) { |
| case MSD_CONNECTION_NOTIFICATION_CHANNEL_SEND: |
| DASSERT(src->u.channel_send.size <= MSD_CHANNEL_SEND_MAX_SIZE); |
| memcpy(dst->u.channel_send.data, src->u.channel_send.data, src->u.channel_send.size); |
| dst->u.channel_send.size = src->u.channel_send.size; |
| break; |
| |
| case MSD_CONNECTION_NOTIFICATION_PERFORMANCE_COUNTERS_READ_COMPLETED: |
| memcpy(&dst->u.perf_counter_result, &src->u.perf_counter_result, |
| sizeof(src->u.perf_counter_result)); |
| break; |
| |
| case MSD_CONNECTION_NOTIFICATION_CONTEXT_KILLED: |
| break; |
| |
| case MSD_CONNECTION_NOTIFICATION_HANDLE_WAIT: |
| dst->u.handle_wait = src->u.handle_wait; |
| break; |
| |
| case MSD_CONNECTION_NOTIFICATION_HANDLE_WAIT_CANCEL: |
| dst->u.handle_wait_cancel = src->u.handle_wait_cancel; |
| break; |
| |
| default: |
| DMESSAGE("Unhandled notification type: %lu", dst->type); |
| DASSERT(false); |
| } |
| } |
| |
| class ZirconPlatformConnection : public fidl::WireServer<fuchsia_gpu_magma::Primary>, |
| public PlatformConnection { |
| public: |
| struct AsyncWait : public async_wait { |
| AsyncWait(ZirconPlatformConnection* connection, zx_handle_t object, zx_signals_t trigger) { |
| this->state = ASYNC_STATE_INIT; |
| this->handler = AsyncWaitHandlerStatic; |
| this->object = object; |
| this->trigger = trigger; |
| this->options = 0; |
| this->connection = connection; |
| } |
| ZirconPlatformConnection* connection; |
| }; |
| |
| struct AsyncTask : public async_task { |
| AsyncTask(ZirconPlatformConnection* connection, msd_notification_t* notification) { |
| this->state = ASYNC_STATE_INIT; |
| this->handler = AsyncTaskHandlerStatic; |
| this->deadline = async_now(connection->async_loop()->dispatcher()); |
| this->connection = connection; |
| CopyNotification(notification, &this->notification); |
| } |
| |
| ZirconPlatformConnection* connection; |
| msd_notification_t notification; |
| }; |
| |
| ZirconPlatformConnection(std::unique_ptr<Delegate> delegate, msd_client_id_t client_id, |
| zx::channel server_notification_endpoint, |
| std::shared_ptr<magma::PlatformEvent> shutdown_event, |
| std::unique_ptr<magma::PlatformHandle> thread_profile) |
| : magma::PlatformConnection(shutdown_event, client_id, std::move(thread_profile)), |
| delegate_(std::move(delegate)), |
| server_notification_endpoint_(std::move(server_notification_endpoint)), |
| async_loop_(&kAsyncLoopConfigNeverAttachToThread), |
| async_wait_shutdown_( |
| this, static_cast<magma::ZirconPlatformEvent*>(shutdown_event.get())->zx_handle(), |
| ZX_EVENT_SIGNALED) { |
| delegate_->SetNotificationCallback(NotificationCallbackStatic, this); |
| } |
| |
| ~ZirconPlatformConnection() { delegate_->SetNotificationCallback(nullptr, 0); } |
| |
| bool Bind(zx::channel server_endpoint); |
| |
| bool HandleRequest() override; |
| |
| bool BeginShutdownWait(); |
| |
| async::Loop* async_loop() { return &async_loop_; } |
| |
| private: |
| static void AsyncWaitHandlerStatic(async_dispatcher_t* dispatcher, async_wait_t* async_wait, |
| zx_status_t status, const zx_packet_signal_t* signal) { |
| auto wait = static_cast<AsyncWait*>(async_wait); |
| wait->connection->AsyncWaitHandler(dispatcher, wait, status, signal); |
| } |
| |
| void AsyncWaitHandler(async_dispatcher_t* dispatcher, AsyncWait* wait, zx_status_t status, |
| const zx_packet_signal_t* signal); |
| |
| // Could occur on an arbitrary thread (see |msd_connection_set_notification_callback|). |
| // MSD must ensure we aren't in the process of destroying our connection. |
| static void NotificationCallbackStatic(void* token, msd_notification_t* notification) { |
| auto connection = static_cast<ZirconPlatformConnection*>(token); |
| zx_status_t status = async_post_task(connection->async_loop()->dispatcher(), |
| new AsyncTask(connection, notification)); |
| if (status != ZX_OK) |
| DLOG("async_post_task failed, status %s", zx_status_get_string(status)); |
| } |
| |
| static void AsyncTaskHandlerStatic(async_dispatcher_t* dispatcher, async_task_t* async_task, |
| zx_status_t status) { |
| auto task = static_cast<AsyncTask*>(async_task); |
| task->connection->AsyncTaskHandler(dispatcher, task, status); |
| delete task; |
| } |
| |
| bool AsyncTaskHandler(async_dispatcher_t* dispatcher, AsyncTask* task, zx_status_t status); |
| |
| void ImportObject(ImportObjectRequestView request, |
| ImportObjectCompleter::Sync& _completer) override; |
| void ImportObject2(ImportObject2RequestView request, |
| ImportObject2Completer::Sync& _completer) override; |
| void ReleaseObject(ReleaseObjectRequestView request, |
| ReleaseObjectCompleter::Sync& _completer) override; |
| void CreateContext(CreateContextRequestView request, |
| CreateContextCompleter::Sync& _completer) override; |
| void DestroyContext(DestroyContextRequestView request, |
| DestroyContextCompleter::Sync& _completer) override; |
| void ExecuteImmediateCommands(ExecuteImmediateCommandsRequestView request, |
| ExecuteImmediateCommandsCompleter::Sync& _completer) override; |
| // DEPRECATED - TODO(fxb/86670) remove |
| void ExecuteCommandBufferWithResources2( |
| ExecuteCommandBufferWithResources2RequestView request, |
| ExecuteCommandBufferWithResources2Completer::Sync& completer) override; |
| void ExecuteCommand(ExecuteCommandRequestView request, |
| ExecuteCommandCompleter::Sync& completer) override; |
| void Flush(FlushRequestView request, FlushCompleter::Sync& _completer) override; |
| void MapBufferGpu(MapBufferGpuRequestView request, |
| MapBufferGpuCompleter::Sync& _completer) override; |
| void UnmapBufferGpu(UnmapBufferGpuRequestView request, |
| UnmapBufferGpuCompleter::Sync& _completer) override; |
| void BufferRangeOp(BufferRangeOpRequestView request, |
| BufferRangeOpCompleter::Sync& completer) override; |
| void EnablePerformanceCounterAccess( |
| EnablePerformanceCounterAccessRequestView request, |
| EnablePerformanceCounterAccessCompleter::Sync& completer) override; |
| void IsPerformanceCounterAccessAllowed( |
| IsPerformanceCounterAccessAllowedRequestView request, |
| IsPerformanceCounterAccessAllowedCompleter::Sync& completer) override; |
| |
| void EnableFlowControl(EnableFlowControlRequestView request, |
| EnableFlowControlCompleter::Sync& _completer) override; |
| |
| std::pair<uint64_t, uint64_t> GetFlowControlCounts() override { |
| return {messages_consumed_, bytes_imported_}; |
| } |
| |
| void EnablePerformanceCounters(EnablePerformanceCountersRequestView request, |
| EnablePerformanceCountersCompleter::Sync& completer) override; |
| void CreatePerformanceCounterBufferPool( |
| CreatePerformanceCounterBufferPoolRequestView request, |
| CreatePerformanceCounterBufferPoolCompleter::Sync& completer) override; |
| void ReleasePerformanceCounterBufferPool( |
| ReleasePerformanceCounterBufferPoolRequestView request, |
| ReleasePerformanceCounterBufferPoolCompleter::Sync& completer) override; |
| void AddPerformanceCounterBufferOffsetsToPool( |
| AddPerformanceCounterBufferOffsetsToPoolRequestView request, |
| AddPerformanceCounterBufferOffsetsToPoolCompleter::Sync& completer) override; |
| void RemovePerformanceCounterBufferFromPool( |
| RemovePerformanceCounterBufferFromPoolRequestView request, |
| RemovePerformanceCounterBufferFromPoolCompleter::Sync& completer) override; |
| void DumpPerformanceCounters(DumpPerformanceCountersRequestView request, |
| DumpPerformanceCountersCompleter::Sync& completer) override; |
| void ClearPerformanceCounters(ClearPerformanceCountersRequestView request, |
| ClearPerformanceCountersCompleter::Sync& completer) override; |
| |
| // Epitaph will be sent on the given completer if provided, else on the server binding. |
| void SetError(fidl::CompleterBase* completer, magma_status_t error); |
| |
| void FlowControl(uint64_t size = 0); |
| |
| // The binding will be valid after a successful |fidl::BindServer| operation, |
| // and back to invalid after this class is unbound from the FIDL dispatcher. |
| cpp17::optional<fidl::ServerBindingRef<fuchsia_gpu_magma::Primary>> server_binding_; |
| |
| std::unique_ptr<Delegate> delegate_; |
| magma_status_t error_{}; |
| zx::channel server_notification_endpoint_; |
| zx::channel performance_counter_event_channel_; |
| async::Loop async_loop_; |
| AsyncWait async_wait_shutdown_; |
| |
| // Flow control |
| bool flow_control_enabled_ = false; |
| uint64_t messages_consumed_ = 0; |
| uint64_t bytes_imported_ = 0; |
| |
| friend class FlowControlChecker; |
| }; |
| |
| } // namespace magma |
| |
| #endif // ZIRCON_PLATFORM_CONNECTION_H |