| // Copyright 2016 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 MSD_INTEL_CONNECTION_H |
| #define MSD_INTEL_CONNECTION_H |
| |
| #include <lib/magma/util/short_macros.h> |
| #include <lib/magma_service/msd.h> |
| |
| #include <list> |
| #include <memory> |
| |
| #include "command_buffer.h" |
| #include "engine_command_streamer.h" |
| #include "msd_intel_pci_device.h" |
| |
| class MsdIntelContext; |
| |
| class MsdIntelConnection { |
| public: |
| class Owner : public PerProcessGtt::Owner { |
| public: |
| virtual ~Owner() = default; |
| |
| virtual void SubmitBatch(std::unique_ptr<MappedBatch> batch) = 0; |
| virtual void DestroyContext(std::shared_ptr<MsdIntelContext> client_context) = 0; |
| }; |
| |
| static std::unique_ptr<MsdIntelConnection> Create(Owner* owner, msd::msd_client_id_t client_id); |
| |
| virtual ~MsdIntelConnection() {} |
| |
| std::shared_ptr<PerProcessGtt> per_process_gtt() { return ppgtt_; } |
| |
| msd::msd_client_id_t client_id() { return client_id_; } |
| |
| void SubmitBatch(std::unique_ptr<MappedBatch> batch) { owner_->SubmitBatch(std::move(batch)); } |
| |
| static std::shared_ptr<MsdIntelContext> CreateContext( |
| std::shared_ptr<MsdIntelConnection> connection); |
| |
| void DestroyContext(std::shared_ptr<MsdIntelContext> context); |
| |
| void SetNotificationCallback(msd::NotificationHandler* handler) { notifications_.Set(handler); } |
| |
| // Called by the device thread when command buffers complete. |
| void SendNotification(std::vector<uint64_t>& buffer_ids) { |
| notifications_.SendBufferIds(buffer_ids); |
| } |
| |
| void SendContextKilled() { |
| notifications_.SendContextKilled(); |
| sent_context_killed_ = true; |
| } |
| |
| // `Callback` should be of type zx_status_t(async_dispatcher_t*). It's called while holding the |
| // notifications_ lock. |
| template <typename Callback> |
| std::optional<zx_status_t> CallWithDispatcher(Callback callback) { |
| return notifications_.CallWithDispatcher(callback); |
| } |
| |
| // Maps |page_count| pages of the given |buffer| at |page_offset| to |gpu_addr| into the |
| // GPU address space belonging to this connection. |
| magma::Status MapBufferGpu(std::shared_ptr<MsdIntelBuffer> buffer, uint64_t gpu_addr, |
| uint64_t page_offset, uint64_t page_count); |
| |
| void ReleaseBuffer(magma::PlatformBuffer* buffer); |
| |
| // A value chosen for historical reasons, just want to prevent sending channel messages |
| // that are too large. |
| static constexpr size_t kMaxUint64PerChannelSend = 510; |
| |
| private: |
| MsdIntelConnection(Owner* owner, std::shared_ptr<PerProcessGtt> ppgtt, |
| msd::msd_client_id_t client_id) |
| : owner_(owner), ppgtt_(std::move(ppgtt)), client_id_(client_id) {} |
| |
| bool sent_context_killed() { return sent_context_killed_; } |
| |
| // The given callback should return when any of the given semaphores are signaled. |
| void ReleaseBuffer( |
| magma::PlatformBuffer* buffer, |
| std::function<magma::Status( |
| std::vector<std::shared_ptr<magma::PlatformSemaphore>>& semaphores, uint32_t timeout_ms)> |
| wait_callback); |
| |
| Owner* owner_; |
| std::shared_ptr<PerProcessGtt> ppgtt_; |
| msd::msd_client_id_t client_id_; |
| bool sent_context_killed_ = false; |
| std::list<std::shared_ptr<MsdIntelContext>> context_list_; |
| |
| class Notifications { |
| public: |
| void SendBufferIds(std::vector<uint64_t>& buffer_ids) { |
| std::lock_guard<std::mutex> lock(mutex_); |
| if (!handler_) |
| return; |
| |
| for (size_t src_index = 0; src_index < buffer_ids.size();) { |
| size_t count = std::min(buffer_ids.size() - src_index, kMaxUint64PerChannelSend); |
| |
| auto start = reinterpret_cast<uint8_t*>(&buffer_ids[src_index]); |
| auto end = reinterpret_cast<uint8_t*>(&buffer_ids[src_index + count]); |
| |
| handler_->NotificationChannelSend(cpp20::span(start, end)); |
| |
| src_index += count; |
| } |
| } |
| |
| void SendContextKilled() { |
| std::lock_guard<std::mutex> lock(mutex_); |
| if (!handler_) |
| return; |
| |
| handler_->ContextKilled(); |
| } |
| |
| template <typename Callback> |
| std::optional<zx_status_t> CallWithDispatcher(Callback callback) { |
| std::lock_guard<std::mutex> lock(mutex_); |
| if (!handler_) |
| return std::nullopt; |
| return {callback(handler_->GetAsyncDispatcher())}; |
| } |
| |
| void Set(msd::NotificationHandler* handler) { |
| std::lock_guard<std::mutex> lock(mutex_); |
| handler_ = handler; |
| } |
| |
| private: |
| msd::NotificationHandler* handler_ = nullptr; |
| std::mutex mutex_; |
| }; |
| |
| Notifications notifications_; |
| |
| friend class TestMsdIntelConnection; |
| }; |
| |
| class MsdIntelAbiConnection : public msd::Connection { |
| public: |
| explicit MsdIntelAbiConnection(std::shared_ptr<MsdIntelConnection> ptr) : ptr_(std::move(ptr)) {} |
| |
| // msd::Connection impl |
| magma_status_t MapBuffer(msd::Buffer& buffer, uint64_t gpu_va, uint64_t offset, uint64_t length, |
| uint64_t flags) override; |
| void ReleaseBuffer(msd::Buffer& buffer) override; |
| |
| void SetNotificationCallback(msd::NotificationHandler* handler) override; |
| |
| std::unique_ptr<msd::Context> CreateContext() override; |
| |
| std::shared_ptr<MsdIntelConnection> ptr() { return ptr_; } |
| |
| private: |
| std::shared_ptr<MsdIntelConnection> ptr_; |
| }; |
| |
| #endif // MSD_INTEL_CONNECTION_H |