blob: 2e3ad28d38891115fb392116e29add3906f85642 [file] [log] [blame]
// 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