| // Copyright 2018 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 "src/media/playback/mediaplayer/graph/payloads/payload_buffer.h" |
| |
| #include <lib/zx/vmar.h> |
| |
| #include <cstdlib> |
| #include <memory> |
| |
| #include "src/lib/fxl/logging.h" |
| |
| namespace media_player { |
| |
| // static |
| fbl::RefPtr<PayloadVmo> PayloadVmo::Create(uint64_t vmo_size, |
| const zx::handle* bti_handle) { |
| FXL_DCHECK(vmo_size != 0); |
| |
| zx::vmo vmo; |
| |
| if (bti_handle != nullptr) { |
| // Create a contiguous VMO. This is a hack that will be removed once the |
| // FIDL buffer allocator is working an integrated. |
| zx_status_t status = zx_vmo_create_contiguous( |
| bti_handle->get(), vmo_size, 0, vmo.reset_and_get_address()); |
| if (status != ZX_OK) { |
| FXL_LOG(ERROR) << "Failed to create contiguous VMO of size " << vmo_size |
| << ", status " << status << "."; |
| return nullptr; |
| } |
| } else { |
| zx_status_t status = zx::vmo::create(vmo_size, 0, &vmo); |
| if (status != ZX_OK) { |
| FXL_LOG(ERROR) << "Failed to create VMO of size " << vmo_size |
| << ", status " << status << "."; |
| return nullptr; |
| } |
| } |
| |
| zx_status_t status; |
| auto result = fbl::MakeRefCounted<PayloadVmo>( |
| std::move(vmo), vmo_size, ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, bti_handle, |
| &status); |
| return status == ZX_OK ? result : nullptr; |
| } |
| |
| // static |
| fbl::RefPtr<PayloadVmo> PayloadVmo::Create(zx::vmo vmo, |
| zx_vm_option_t map_flags) { |
| uint64_t vmo_size; |
| zx_status_t status = vmo.get_size(&vmo_size); |
| if (status != ZX_OK) { |
| FXL_LOG(ERROR) << "Failed to get VMO size."; |
| return nullptr; |
| } |
| |
| auto result = fbl::MakeRefCounted<PayloadVmo>(std::move(vmo), vmo_size, |
| map_flags, nullptr, &status); |
| return status == ZX_OK ? result : nullptr; |
| } |
| |
| PayloadVmo::PayloadVmo(zx::vmo vmo, uint64_t vmo_size, zx_vm_option_t map_flags, |
| const zx::handle* bti_handle, zx_status_t* status_out) |
| : vmo_(std::move(vmo)), size_(vmo_size) { |
| FXL_DCHECK(vmo_); |
| FXL_DCHECK(vmo_size != 0); |
| FXL_DCHECK(status_out != nullptr); |
| |
| zx_status_t status = vmo_mapper_.Map(vmo_, 0, size_, map_flags, nullptr); |
| if (status != ZX_OK) { |
| FXL_LOG(ERROR) << "Failed to map VMO, status " << status; |
| *status_out = status; |
| return; |
| } |
| |
| *status_out = ZX_OK; |
| } |
| |
| zx::vmo PayloadVmo::Duplicate(zx_rights_t rights) { |
| zx::vmo duplicate; |
| zx_status_t status = vmo_.duplicate(rights, &duplicate); |
| if (status != ZX_OK) { |
| FXL_LOG(FATAL) << "Failed to duplicate VMO, status " << status; |
| } |
| |
| return duplicate; |
| } |
| |
| // static |
| fbl::RefPtr<PayloadBuffer> PayloadBuffer::Create(uint64_t size, void* data, |
| Recycler recycler) { |
| return fbl::AdoptRef(new PayloadBuffer(size, data, std::move(recycler))); |
| } |
| |
| // static |
| fbl::RefPtr<PayloadBuffer> PayloadBuffer::Create(uint64_t size, void* data, |
| fbl::RefPtr<PayloadVmo> vmo, |
| uint64_t offset, |
| Recycler recycler) { |
| return fbl::AdoptRef( |
| new PayloadBuffer(size, data, vmo, offset, std::move(recycler))); |
| } |
| |
| // static |
| fbl::RefPtr<PayloadBuffer> PayloadBuffer::CreateWithMalloc(uint64_t size) { |
| FXL_DCHECK(size > 0); |
| // TODO: Once we use C++17, std::aligned_alloc should work. |
| // |aligned_alloc| requires the size to the aligned. |
| return PayloadBuffer::Create(size, |
| aligned_alloc(PayloadBuffer::kByteAlignment, |
| PayloadBuffer::AlignUp(size)), |
| [](PayloadBuffer* payload_buffer) { |
| FXL_DCHECK(payload_buffer); |
| std::free(payload_buffer->data()); |
| // The |PayloadBuffer| deletes itself. |
| }); |
| } |
| |
| PayloadBuffer::PayloadBuffer(uint64_t size, void* data, Recycler recycler) |
| : size_(size), data_(data), recycler_(std::move(recycler)) { |
| FXL_DCHECK(size_ != 0); |
| FXL_DCHECK(data_ != nullptr); |
| FXL_DCHECK(recycler_); |
| } |
| |
| PayloadBuffer::PayloadBuffer(uint64_t size, void* data, |
| fbl::RefPtr<PayloadVmo> vmo, |
| uint64_t offset_in_vmo, Recycler recycler) |
| : size_(size), |
| data_(data), |
| vmo_(vmo), |
| offset_(offset_in_vmo), |
| recycler_(std::move(recycler)) { |
| FXL_DCHECK(size_ != 0); |
| FXL_DCHECK(vmo_); |
| FXL_DCHECK((data_ == nullptr) || |
| (reinterpret_cast<uint8_t*>(vmo_->start()) + offset_ == |
| reinterpret_cast<uint8_t*>(data_))); |
| FXL_DCHECK(recycler_); |
| |
| // TODO(dalesat): Remove this check when we support unmappable VMOs. |
| FXL_DCHECK(data_ != nullptr); |
| } |
| |
| PayloadBuffer::~PayloadBuffer() { |
| FXL_DCHECK(!recycler_) << "PayloadBuffers must delete themselves."; |
| } |
| |
| void PayloadBuffer::AfterRecycling(Action action) { |
| FXL_DCHECK(!after_recycling_) << "AfterRecycling may only be called once."; |
| after_recycling_ = std::move(action); |
| } |
| |
| void PayloadBuffer::fbl_recycle() { |
| FXL_DCHECK(recycler_ != nullptr); |
| |
| recycler_(this); |
| // This tells the destructor that deletion is being done properly. |
| recycler_ = nullptr; |
| |
| if (after_recycling_) { |
| after_recycling_(this); |
| } |
| |
| delete this; |
| } |
| |
| } // namespace media_player |