| // Copyright 2019 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. |
| |
| #include "allocator.h" |
| |
| #include <lib/fidl-async-2/fidl_struct.h> |
| #include <lib/fidl-utils/bind.h> |
| #include <lib/fidl/internal.h> |
| #include <lib/zx/channel.h> |
| #include <lib/zx/event.h> |
| #include <zircon/fidl.h> |
| |
| #include <ddk/trace/event.h> |
| |
| #include "logical_buffer_collection.h" |
| |
| namespace sysmem_driver { |
| |
| namespace { |
| |
| constexpr uint32_t kConcurrencyCap = 64; |
| |
| } // namespace |
| |
| const fuchsia_sysmem_Allocator_ops_t Allocator::kOps = { |
| fidl::Binder<Allocator>::BindMember<&Allocator::AllocateNonSharedCollection>, |
| fidl::Binder<Allocator>::BindMember<&Allocator::AllocateSharedCollection>, |
| fidl::Binder<Allocator>::BindMember<&Allocator::BindSharedCollection>, |
| fidl::Binder<Allocator>::BindMember<&Allocator::ValidateBufferCollectionToken>, |
| fidl::Binder<Allocator>::BindMember<&Allocator::SetDebugClientInfo>, |
| }; |
| |
| Allocator::Allocator(Device* parent_device) |
| : FidlServer(parent_device->dispatcher(), "sysmem allocator", kConcurrencyCap), |
| parent_device_(parent_device) { |
| // nothing else to do here |
| } |
| |
| Allocator::~Allocator() { LogInfo("~Allocator"); } |
| |
| zx_status_t Allocator::AllocateNonSharedCollection(zx_handle_t buffer_collection_request_param) { |
| TRACE_DURATION("gfx", "Allocator::AllocateNonSharedCollection"); |
| zx::channel buffer_collection_request(buffer_collection_request_param); |
| |
| // The AllocateCollection() message skips past the token stage because the |
| // client is also the only participant (probably a temp/test client). Real |
| // clients are encouraged to use AllocateSharedCollection() instead, so that |
| // the client can share the LogicalBufferCollection with other participants. |
| // |
| // Because this is a degenerate way to use sysmem, we implement this method |
| // in terms of the non-degenerate way. |
| // |
| // This code is essentially the same as what a client would do if a client |
| // wanted to skip the BufferCollectionToken stage without using |
| // AllocateCollection(). Essentially, this code is here just so clients |
| // that don't need to share their collection don't have to write this code, |
| // and can share this code instead. |
| |
| // Create a local token. |
| zx::channel token_client; |
| zx::channel token_server; |
| zx_status_t status = zx::channel::create(0, &token_client, &token_server); |
| if (status != ZX_OK) { |
| LogError( |
| "Allocator::AllocateCollection() zx::channel::create() failed " |
| "- status: %d", |
| status); |
| // ~buffer_collection_request |
| // |
| // Returning an error here causes the sysmem connection to drop also, |
| // which seems like a good idea (more likely to recover overall) given |
| // the nature of the error. |
| return status; |
| } |
| |
| // The server end of the local token goes to Create(), and the client end |
| // goes to BindSharedCollection(). The BindSharedCollection() will figure |
| // out which token we're talking about based on the koid(s), as usual. |
| LogicalBufferCollection::Create(std::move(token_server), parent_device_); |
| LogicalBufferCollection::BindSharedCollection(parent_device_, std::move(token_client), |
| std::move(buffer_collection_request), |
| client_info_ ? &*client_info_ : nullptr); |
| |
| // Now the client can SetConstraints() on the BufferCollection, etc. The |
| // client didn't have to hassle with the BufferCollectionToken, which is the |
| // sole upside of the client using this message over |
| // AllocateSharedCollection(). |
| return ZX_OK; |
| } |
| |
| zx_status_t Allocator::AllocateSharedCollection(zx_handle_t token_request_param) { |
| TRACE_DURATION("gfx", "Allocator::AllocateSharedCollection"); |
| zx::channel token_request(token_request_param); |
| |
| // The LogicalBufferCollection is self-owned / owned by all the channels it |
| // serves. |
| // |
| // There's no channel served directly by the LogicalBufferCollection. |
| // Instead LogicalBufferCollection owns all the FidlServer instances that |
| // each own a channel. |
| // |
| // Initially there's only a channel to the first BufferCollectionToken. We |
| // go ahead and allocate the LogicalBufferCollection here since the |
| // LogicalBufferCollection associates all the BufferCollectionToken and |
| // BufferCollection bindings to the same LogicalBufferCollection. |
| LogicalBufferCollection::Create(std::move(token_request), parent_device_); |
| return ZX_OK; |
| } |
| |
| zx_status_t Allocator::BindSharedCollection(zx_handle_t token_param, |
| zx_handle_t buffer_collection_request_param) { |
| TRACE_DURATION("gfx", "Allocator::BindSharedCollection"); |
| zx::channel token(token_param); |
| zx::channel buffer_collection_request(buffer_collection_request_param); |
| |
| // The BindSharedCollection() message is about a supposed-to-be-pre-existing |
| // logical BufferCollection, but the only association we have to that |
| // BufferCollection is the client end of a BufferCollectionToken channel |
| // being handed in via token_param. To find any associated BufferCollection |
| // we have to look it up by koid. The koid table is held by |
| // BufferCollection, so delegate over to BufferCollection for this request. |
| LogicalBufferCollection::BindSharedCollection(parent_device_, std::move(token), |
| std::move(buffer_collection_request), |
| client_info_ ? &*client_info_ : nullptr); |
| return ZX_OK; |
| } |
| |
| zx_status_t Allocator::ValidateBufferCollectionToken(zx_koid_t token_server_koid, fidl_txn_t* txn) { |
| BindingType::Txn::RecognizeTxn(txn); |
| zx_status_t status = |
| LogicalBufferCollection::ValidateBufferCollectionToken(parent_device_, token_server_koid); |
| ZX_DEBUG_ASSERT(status == ZX_OK || status == ZX_ERR_NOT_FOUND); |
| return fuchsia_sysmem_AllocatorValidateBufferCollectionToken_reply(txn, status == ZX_OK); |
| } |
| |
| zx_status_t Allocator::SetDebugClientInfo(const char* name_data, size_t name_size, uint64_t id) { |
| client_info_.emplace(); |
| client_info_->name = std::string(name_data, name_size); |
| client_info_->id = id; |
| return ZX_OK; |
| } |
| |
| } // namespace sysmem_driver |