blob: 85eb3d6a9aced2e7e330bcc2f223a260dde5a8e2 [file] [log] [blame]
// 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 "task.h"
#include <ddk/debug.h>
#include <fbl/alloc_checker.h>
#include <lib/syslog/global.h>
#include <stdint.h>
#include <zircon/types.h>
#include <memory>
namespace gdc {
zx_status_t Task::GetInputBufferPhysAddr(uint32_t input_buffer_index,
zx_paddr_t* out) const {
if (input_buffer_index >= input_buffers_.size() || out == nullptr) {
return ZX_ERR_INVALID_ARGS;
} else {
*out = input_buffers_[input_buffer_index].region(0).phys_addr;
}
return ZX_OK;
}
zx_status_t Task::InitBuffers(
const buffer_collection_info_t* input_buffer_collection,
const buffer_collection_info_t* output_buffer_collection,
const zx::vmo& config_vmo, const zx::bti& bti) {
if (!IsBufferCollectionValid(input_buffer_collection) ||
!IsBufferCollectionValid(output_buffer_collection)) {
return ZX_ERR_INVALID_ARGS;
}
// Initialize the VMOPool and pin the output buffers
zx::vmo output_vmos[countof(output_buffer_collection->vmos)];
for (uint32_t i = 0; i < output_buffer_collection->buffer_count; ++i) {
output_vmos[i] = zx::vmo(output_buffer_collection->vmos[i]);
}
zx_status_t status =
output_buffers_.Init(output_vmos, output_buffer_collection->buffer_count);
if (status != ZX_OK) {
FX_LOG(ERROR, "%s: Unable to Init VmoPool \n", __func__);
return status;
}
// Release the vmos so that the buffer collection could be reused.
for (uint32_t i = 0; i < output_buffer_collection->buffer_count; ++i) {
// output_buffer_collection already has the handle so its okay to discard
// this one.
__UNUSED zx_handle_t vmo = output_vmos[i].release();
}
status = output_buffers_.PinVmos(bti, fzl::VmoPool::RequireContig::Yes,
fzl::VmoPool::RequireLowMem::Yes);
if (status != ZX_OK) {
FX_LOG(ERROR, "%s: Unable to pin buffers \n", __func__);
return status;
}
// Pin the input buffers.
fbl::AllocChecker ac;
input_buffers_ = fbl ::Array<fzl::PinnedVmo>(
new (&ac) fzl::PinnedVmo[input_buffer_collection->buffer_count],
input_buffer_collection->buffer_count);
if (!ac.check()) {
return ZX_ERR_NO_MEMORY;
}
for (uint32_t i = 0; i < input_buffer_collection->buffer_count; ++i) {
zx::vmo vmo(input_buffer_collection->vmos[i]);
status =
input_buffers_[i].Pin(vmo, bti, ZX_BTI_CONTIGUOUS | ZX_VM_PERM_READ);
// Release the vmos so that the buffer collection could be reused.
// input_buffer_collection already has the handle so its okay to discard
// this one.
__UNUSED zx_handle_t handle = vmo.release();
if (status != ZX_OK) {
FX_LOG(ERROR, "%s: Unable to pin buffers \n", __func__);
return status;
}
if (input_buffers_[i].region_count() != 1) {
FX_LOG(ERROR, "%s: buffer is not contiguous", __func__);
return ZX_ERR_NO_MEMORY;
}
}
// Pin the Config VMO.
status = config_vmo_pinned_.Pin(config_vmo, bti,
ZX_BTI_CONTIGUOUS | ZX_VM_PERM_READ);
if (status != ZX_OK) {
FX_LOG(ERROR, "%s: Failed to pin config VMO\n", __func__);
return status;
}
if (config_vmo_pinned_.region_count() != 1) {
FX_LOG(ERROR, "%s: buffer is not contiguous", __func__);
return ZX_ERR_NO_MEMORY;
}
return status;
}
// Validates the buffer collection.
bool Task::IsBufferCollectionValid(
const buffer_collection_info_t* buffer_collection) const {
if (buffer_collection == nullptr || buffer_collection->buffer_count == 0 ||
buffer_collection->buffer_count > countof(buffer_collection->vmos) ||
buffer_collection->format.image.pixel_format.type !=
fuchsia_sysmem_PixelFormatType_NV12) {
return false;
}
return true;
}
// static
zx_status_t Task::Create(
const buffer_collection_info_t* input_buffer_collection,
const buffer_collection_info_t* output_buffer_collection,
const zx::vmo& config_vmo, const gdc_callback_t* callback,
const zx::bti& bti, std::unique_ptr<Task>* out) {
if (callback == nullptr || out == nullptr) {
return ZX_ERR_INVALID_ARGS;
}
fbl::AllocChecker ac;
auto task = std::unique_ptr<Task>(new (&ac) Task());
if (!ac.check()) {
return ZX_ERR_NO_MEMORY;
}
zx_status_t status = task->InitBuffers(
input_buffer_collection, output_buffer_collection, config_vmo, bti);
if (status != ZX_OK) {
FX_LOG(ERROR, "%s: InitBuffers Failed\n", __func__);
}
task->callback_ = callback;
*out = std::move(task);
return status;
}
} // namespace gdc