| // 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_CONTEXT_H |
| #define MSD_INTEL_CONTEXT_H |
| |
| #include <lib/async/cpp/wait.h> |
| #include <lib/magma/platform/platform_logger.h> |
| #include <lib/magma/util/status.h> |
| #include <lib/magma_service/msd.h> |
| |
| #include <map> |
| #include <memory> |
| #include <queue> |
| #include <set> |
| |
| #include "command_buffer.h" |
| #include "msd_intel_buffer.h" |
| #include "ppgtt.h" |
| #include "ringbuffer.h" |
| #include "types.h" |
| |
| class MsdIntelConnection; |
| |
| // Base context, not tied to a connection. |
| class MsdIntelContext { |
| public: |
| // Context for handling a wait semaphore. |
| class HandleWaitContext { |
| public: |
| HandleWaitContext(MsdIntelContext* context, EngineCommandStreamerId id, zx::handle object, |
| std::shared_ptr<magma::PlatformSemaphore> semaphore); |
| |
| ~HandleWaitContext() { waiter_.Cancel(); } |
| |
| zx_status_t Begin(async_dispatcher_t* dispatcher) { return waiter_.Begin(dispatcher); } |
| |
| EngineCommandStreamerId id() const { return id_; } |
| const std::shared_ptr<magma::PlatformSemaphore>& semaphore() const { return semaphore_; } |
| |
| private: |
| void Handler(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status, |
| const zx_packet_signal_t* signal); |
| |
| MsdIntelContext* context_; |
| EngineCommandStreamerId id_; |
| zx::handle object_; |
| std::shared_ptr<magma::PlatformSemaphore> semaphore_; |
| async::WaitMethod<HandleWaitContext, &HandleWaitContext::Handler> waiter_; |
| }; |
| |
| explicit MsdIntelContext(std::shared_ptr<AddressSpace> address_space) |
| : address_space_(std::move(address_space)) { |
| DASSERT(address_space_); |
| } |
| |
| MsdIntelContext(std::shared_ptr<AddressSpace> address_space, |
| std::weak_ptr<MsdIntelConnection> connection) |
| : address_space_(std::move(address_space)), connection_(std::move(connection)) {} |
| |
| void SetTargetCommandStreamer(EngineCommandStreamerId id) { |
| target_command_streamers_.insert(id); |
| presubmit_map_.insert({id, PerEnginePresubmit{}}); |
| } |
| |
| std::set<EngineCommandStreamerId> GetTargetCommandStreamers() { |
| return target_command_streamers_; |
| } |
| |
| void SetEngineState(EngineCommandStreamerId id, std::unique_ptr<MsdIntelBuffer> context_buffer, |
| std::unique_ptr<Ringbuffer> ringbuffer); |
| |
| bool Map(std::shared_ptr<AddressSpace> address_space, EngineCommandStreamerId id); |
| bool Unmap(EngineCommandStreamerId id); |
| |
| // The HW context state refers to the indirect context batch, so keep a reference to the batch |
| // and its underlying GPU mapping. |
| void SetIndirectContextBatch(std::shared_ptr<IndirectContextBatch> batch) { |
| indirect_context_batch_ = std::move(batch); |
| } |
| |
| std::weak_ptr<MsdIntelConnection> connection() { return connection_; } |
| |
| bool killed() const { return killed_; } |
| |
| void Kill(); |
| |
| size_t GetQueueSize(EngineCommandStreamerId id) { |
| auto iter = presubmit_map_.find(id); |
| DASSERT(iter != presubmit_map_.end()); |
| |
| PerEnginePresubmit& presubmit = iter->second; |
| |
| return presubmit.queue.size(); |
| } |
| |
| // Gets the gpu address of the context buffer if mapped. |
| bool GetGpuAddress(EngineCommandStreamerId id, gpu_addr_t* addr_out); |
| bool GetRingbufferGpuAddress(EngineCommandStreamerId id, gpu_addr_t* addr_out); |
| |
| MsdIntelBuffer* get_context_buffer(EngineCommandStreamerId id) { |
| auto iter = state_map_.find(id); |
| return iter == state_map_.end() ? nullptr : iter->second.context_buffer.get(); |
| } |
| |
| void* GetCachedContextBufferCpuAddr(EngineCommandStreamerId id) { |
| auto iter = state_map_.find(id); |
| if (iter == state_map_.end()) |
| return nullptr; |
| if (!iter->second.context_buffer_cpu_addr) { |
| MsdIntelBuffer* context_buffer = iter->second.context_buffer.get(); |
| if (!context_buffer) |
| return nullptr; |
| if (!context_buffer->platform_buffer()->MapCpu(&iter->second.context_buffer_cpu_addr)) |
| return DRETP(nullptr, "Failed to map context buffer"); |
| } |
| return iter->second.context_buffer_cpu_addr; |
| } |
| |
| Ringbuffer* get_ringbuffer(EngineCommandStreamerId id) { |
| auto iter = state_map_.find(id); |
| return iter == state_map_.end() ? nullptr : iter->second.ringbuffer.get(); |
| } |
| |
| bool IsInitializedForEngine(EngineCommandStreamerId id) { |
| return state_map_.find(id) != state_map_.end(); |
| } |
| |
| std::queue<std::unique_ptr<MappedBatch>>& pending_batch_queue(EngineCommandStreamerId id) { |
| auto iter = state_map_.find(id); |
| DASSERT(iter != state_map_.end()); |
| return iter->second.pending_batch_queue; |
| } |
| |
| std::shared_ptr<AddressSpace> exec_address_space() { return address_space_; } |
| |
| magma::Status SubmitCommandBuffer(std::unique_ptr<CommandBuffer> cmd_buf); |
| magma::Status SubmitBatch(std::unique_ptr<MappedBatch> batch); |
| |
| std::vector<std::shared_ptr<magma::PlatformSemaphore>> GetWaitSemaphores( |
| EngineCommandStreamerId id) const; |
| |
| void UpdateWaitSet(EngineCommandStreamerId id); |
| void Shutdown(); |
| |
| private: |
| void AddToWaitset(EngineCommandStreamerId id, std::shared_ptr<MsdIntelConnection> connection, |
| std::shared_ptr<magma::PlatformSemaphore> semaphore); |
| void WaitComplete(HandleWaitContext* wait_context, zx_status_t status); |
| magma::Status ProcessPresubmitQueue(EngineCommandStreamerId id); |
| |
| struct PerEngineState { |
| std::shared_ptr<MsdIntelBuffer> context_buffer; |
| std::unique_ptr<GpuMapping> context_mapping; |
| std::unique_ptr<Ringbuffer> ringbuffer; |
| std::queue<std::unique_ptr<MappedBatch>> pending_batch_queue; |
| gpu_addr_t ringbuffer_gpu_addr = 0; |
| void* context_buffer_cpu_addr = nullptr; |
| }; |
| |
| std::shared_ptr<IndirectContextBatch> indirect_context_batch_; |
| std::set<EngineCommandStreamerId> target_command_streamers_; |
| std::map<EngineCommandStreamerId, PerEngineState> state_map_; |
| std::shared_ptr<AddressSpace> address_space_; |
| |
| std::weak_ptr<MsdIntelConnection> connection_; |
| |
| struct PerEnginePresubmit { |
| // The wait set tracks pending semaphores for the head of the presubmit queue |
| std::vector<std::unique_ptr<HandleWaitContext>> wait_set; |
| std::queue<std::unique_ptr<MappedBatch>> queue; |
| }; |
| |
| std::map<EngineCommandStreamerId, PerEnginePresubmit> presubmit_map_; |
| bool killed_ = false; |
| |
| friend class TestContext; |
| }; |
| |
| class MsdIntelAbiContext : public msd::Context { |
| public: |
| explicit MsdIntelAbiContext(std::shared_ptr<MsdIntelContext> ptr) : ptr_(std::move(ptr)) {} |
| |
| ~MsdIntelAbiContext() override; |
| |
| std::shared_ptr<MsdIntelContext> ptr() { return ptr_; } |
| |
| magma_status_t ExecuteCommandBufferWithResources(msd::magma_command_buffer* command_buffer, |
| magma_exec_resource* exec_resources, |
| msd::Buffer** buffers, |
| msd::Semaphore** wait_semaphores, |
| msd::Semaphore** signal_semaphores) override; |
| |
| private: |
| std::shared_ptr<MsdIntelContext> ptr_; |
| }; |
| |
| #endif // MSD_INTEL_CONTEXT_H |