blob: 111dbfbb92f92934211330766a7f9ecd2d93b2cc [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/vmo_buffer.h"
#include <zircon/rights.h>
#include <algorithm>
#include "base/bits.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/memory/page_size.h"
namespace media {
// static
fuchsia::sysmem::BufferCollectionConstraints
VmoBuffer::GetRecommendedConstraints(size_t min_buffer_count,
absl::optional<size_t> min_buffer_size,
bool writable) {
fuchsia::sysmem::BufferCollectionConstraints buffer_constraints;
buffer_constraints.usage.cpu = fuchsia::sysmem::cpuUsageRead;
if (writable)
buffer_constraints.usage.cpu |= fuchsia::sysmem::cpuUsageWrite;
buffer_constraints.min_buffer_count = min_buffer_count;
if (min_buffer_size) {
buffer_constraints.has_buffer_memory_constraints = true;
buffer_constraints.buffer_memory_constraints.min_size_bytes =
min_buffer_size.value();
buffer_constraints.buffer_memory_constraints.ram_domain_supported = true;
buffer_constraints.buffer_memory_constraints.cpu_domain_supported = true;
}
return buffer_constraints;
}
// static
std::vector<VmoBuffer> VmoBuffer::CreateBuffersFromSysmemCollection(
fuchsia::sysmem::BufferCollectionInfo_2* info,
bool writable) {
std::vector<VmoBuffer> buffers;
buffers.resize(info->buffer_count);
fuchsia::sysmem::BufferMemorySettings& settings =
info->settings.buffer_settings;
for (size_t i = 0; i < info->buffer_count; ++i) {
fuchsia::sysmem::VmoBuffer& buffer = info->buffers[i];
if (!buffers[i].Initialize(std::move(buffer.vmo), writable,
buffer.vmo_usable_start, settings.size_bytes,
settings.coherency_domain)) {
return {};
}
}
return buffers;
}
VmoBuffer::VmoBuffer() = default;
VmoBuffer::~VmoBuffer() {
if (!base_address_) {
return;
}
zx_status_t status = zx::vmar::root_self()->unmap(
reinterpret_cast<uintptr_t>(base_address_), mapped_size());
ZX_DCHECK(status == ZX_OK, status) << "zx_vmar_unmap";
}
VmoBuffer::VmoBuffer(VmoBuffer&&) = default;
VmoBuffer& VmoBuffer::operator=(VmoBuffer&&) = default;
bool VmoBuffer::Initialize(zx::vmo vmo,
bool writable,
size_t offset,
size_t size,
fuchsia::sysmem::CoherencyDomain coherency_domain) {
DCHECK(!base_address_);
DCHECK(vmo);
writable_ = writable;
offset_ = offset;
size_ = size;
coherency_domain_ = coherency_domain;
zx_vm_option_t options = ZX_VM_PERM_READ;
if (writable)
options |= ZX_VM_PERM_WRITE;
uintptr_t addr;
zx_status_t status =
zx::vmar::root_self()->map(options, /*vmar_offset=*/0, vmo,
/*vmo_offset=*/0, mapped_size(), &addr);
if (status != ZX_OK) {
ZX_DLOG(ERROR, status) << "zx_vmar_map";
return false;
}
vmo_ = std::move(vmo);
base_address_ = reinterpret_cast<uint8_t*>(addr);
return true;
}
size_t VmoBuffer::Read(size_t offset, base::span<uint8_t> data) {
if (offset >= size_)
return 0U;
size_t bytes_to_fill = std::min(size_ - offset, data.size());
FlushCache(offset, bytes_to_fill, /*invalidate=*/true);
memcpy(data.data(), base_address_ + offset_ + offset, bytes_to_fill);
return bytes_to_fill;
}
size_t VmoBuffer::Write(base::span<const uint8_t> data) {
DCHECK(writable_);
size_t bytes_to_fill = std::min(size_, data.size());
memcpy(base_address_ + offset_, data.data(), bytes_to_fill);
FlushCache(0, bytes_to_fill, /*invalidate=*/false);
return bytes_to_fill;
}
base::span<const uint8_t> VmoBuffer::GetMemory() {
FlushCache(0, size_, /*invalidate=*/true);
return base::make_span(base_address_ + offset_, size_);
}
base::span<uint8_t> VmoBuffer::GetWritableMemory() {
DCHECK(writable_);
return base::make_span(base_address_ + offset_, size_);
}
void VmoBuffer::FlushCache(size_t flush_offset,
size_t flush_size,
bool invalidate) {
DCHECK_LE(flush_size, size_ - flush_offset);
if (coherency_domain_ != fuchsia::sysmem::CoherencyDomain::RAM)
return;
uint8_t* address = base_address_ + offset_ + flush_offset;
uint32_t options = ZX_CACHE_FLUSH_DATA;
if (invalidate)
options |= ZX_CACHE_FLUSH_INVALIDATE;
zx_status_t status = zx_cache_flush(address, flush_size, options);
ZX_DCHECK(status == ZX_OK, status) << "zx_cache_flush";
}
size_t VmoBuffer::mapped_size() {
return base::bits::AlignUp(offset_ + size_, base::GetPageSize());
}
zx::vmo VmoBuffer::Duplicate(bool writable) {
zx_rights_t rights = ZX_RIGHT_DUPLICATE | ZX_RIGHT_TRANSFER | ZX_RIGHT_READ |
ZX_RIGHT_MAP | ZX_RIGHT_GET_PROPERTY;
if (writable)
rights |= ZX_RIGHT_WRITE;
zx::vmo vmo;
zx_status_t status = vmo_.duplicate(rights, &vmo);
ZX_CHECK(status == ZX_OK, status) << "zx_handle_duplicate";
return vmo;
}
} // namespace media