blob: 4c5d86dbeb11a334dc2da9d341c73ad9ed7d5566 [file] [log] [blame]
// Copyright 2021 The Chromium 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 "media/fuchsia/common/sysmem_client.h"
#include <lib/sys/cpp/component_context.h>
#include <zircon/rights.h>
#include <algorithm>
#include "base/bind.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/fuchsia/process_context.h"
#include "base/process/process_handle.h"
#include "media/fuchsia/common/vmo_buffer.h"
namespace media {
SysmemCollectionClient::SysmemCollectionClient(
fuchsia::sysmem::Allocator* allocator,
fuchsia::sysmem::BufferCollectionTokenPtr collection_token)
: allocator_(allocator), collection_token_(std::move(collection_token)) {
DCHECK(allocator_);
DCHECK(collection_token_);
}
SysmemCollectionClient::~SysmemCollectionClient() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (collection_)
collection_->Close();
}
void SysmemCollectionClient::Initialize(
fuchsia::sysmem::BufferCollectionConstraints constraints,
base::StringPiece name,
uint32_t name_priority) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
writable_ = (constraints.usage.cpu & fuchsia::sysmem::cpuUsageWrite) ==
fuchsia::sysmem::cpuUsageWrite;
allocator_->BindSharedCollection(std::move(collection_token_),
collection_.NewRequest());
collection_.set_error_handler(
fit::bind_member(this, &SysmemCollectionClient::OnError));
collection_->SetName(name_priority, std::string(name));
// If Sync() is not required then constraints can be set immediately.
if (sync_completion_closures_.empty()) {
collection_->SetConstraints(/*have_constraints=*/true,
std::move(constraints));
return;
}
sync_completion_closures_.push_back(
base::BindOnce(&fuchsia::sysmem::BufferCollection::SetConstraints,
base::Unretained(collection_.get()),
/*have_constraints=*/true, std::move(constraints)));
collection_->Sync(
fit::bind_member(this, &SysmemCollectionClient::OnSyncComplete));
}
void SysmemCollectionClient::CreateSharedToken(
GetSharedTokenCB cb,
base::StringPiece debug_client_name,
uint64_t debug_client_id) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(collection_token_);
fuchsia::sysmem::BufferCollectionTokenPtr token;
collection_token_->Duplicate(ZX_RIGHT_SAME_RIGHTS, token.NewRequest());
if (!debug_client_name.empty()) {
token->SetDebugClientInfo(std::string(debug_client_name), debug_client_id);
}
sync_completion_closures_.push_back(
base::BindOnce(std::move(cb), std::move(token)));
}
void SysmemCollectionClient::AcquireBuffers(AcquireBuffersCB cb) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(!collection_token_);
if (!collection_) {
std::move(cb).Run({}, {});
return;
}
acquire_buffers_cb_ = std::move(cb);
collection_->WaitForBuffersAllocated(
fit::bind_member(this, &SysmemCollectionClient::OnBuffersAllocated));
}
void SysmemCollectionClient::OnSyncComplete() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
std::vector<base::OnceClosure> sync_closures =
std::move(sync_completion_closures_);
for (auto& cb : sync_closures) {
std::move(cb).Run();
}
}
void SysmemCollectionClient::OnBuffersAllocated(
zx_status_t status,
fuchsia::sysmem::BufferCollectionInfo_2 buffer_collection_info) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (status != ZX_OK) {
ZX_LOG(ERROR, status) << "Failed to allocate sysmem buffers.";
OnError(status);
return;
}
if (acquire_buffers_cb_) {
auto buffers = VmoBuffer::CreateBuffersFromSysmemCollection(
&buffer_collection_info, writable_);
std::move(acquire_buffers_cb_)
.Run(std::move(buffers), buffer_collection_info.settings);
}
}
void SysmemCollectionClient::OnError(zx_status_t status) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
ZX_DLOG(ERROR, status) << "Connection to BufferCollection was disconnected.";
collection_.Unbind();
if (acquire_buffers_cb_)
std::move(acquire_buffers_cb_).Run({}, {});
}
SysmemAllocatorClient::SysmemAllocatorClient(base::StringPiece client_name) {
allocator_ = base::ComponentContextForProcess()
->svc()
->Connect<fuchsia::sysmem::Allocator>();
allocator_->SetDebugClientInfo(std::string(client_name),
base::GetCurrentProcId());
allocator_.set_error_handler([](zx_status_t status) {
// Just log a warning. We will handle BufferCollection the failure when
// trying to create a new BufferCollection.
ZX_DLOG(WARNING, status)
<< "The fuchsia.sysmem.Allocator channel was disconnected.";
});
}
SysmemAllocatorClient::~SysmemAllocatorClient() = default;
fuchsia::sysmem::BufferCollectionTokenPtr
SysmemAllocatorClient::CreateNewToken() {
fuchsia::sysmem::BufferCollectionTokenPtr collection_token;
allocator_->AllocateSharedCollection(collection_token.NewRequest());
return collection_token;
}
std::unique_ptr<SysmemCollectionClient>
SysmemAllocatorClient::AllocateNewCollection() {
return std::make_unique<SysmemCollectionClient>(allocator_.get(),
CreateNewToken());
}
std::unique_ptr<SysmemCollectionClient>
SysmemAllocatorClient::BindSharedCollection(
fuchsia::sysmem::BufferCollectionTokenPtr token) {
return std::make_unique<SysmemCollectionClient>(allocator_.get(),
std::move(token));
}
} // namespace media