blob: 9f76745c9a213a30b3c7f039d8b678c6d6249bdd [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 "processing_node.h"
#include <lib/ddk/debug.h>
#include <lib/ddk/trace/event.h>
#include <zircon/assert.h>
#include <zircon/errors.h>
#include <zircon/types.h>
namespace camera {
// Returns a string describing the provided source location.
static std::string Whence(const cpp20::source_location& location) {
std::string whence = location.file_name() ? location.file_name() : "<unknown>";
whence += ":" + std::to_string(location.line()) + " (";
whence += location.function_name() ? location.function_name() : "<unknown>";
whence += ")";
return whence;
}
ProcessNode::ProcessNode(async_dispatcher_t* dispatcher, NodeType type,
BufferAttachments attachments, FrameCallback frame_callback)
: dispatcher_(dispatcher),
type_(type),
attachments_(attachments),
frame_callback_(std::move(frame_callback)),
hwaccel_callbacks_{
.frame{.frame_ready = &ProcessNode::StaticHwFrameReady, .ctx = this},
.res_change{.frame_resolution_changed = &ProcessNode::StaticHwFrameResolutionChanged,
.ctx = this},
.remove_task{.task_removed = &ProcessNode::StaticHwTaskRemoved, .ctx = this}} {}
ProcessNode::~ProcessNode() {
zxlogf(INFO, "~ProcessNode(%s)", label_.c_str());
ZX_ASSERT_MSG(shutdown_state_.requested, "Caller destroying node without requesting shutdown.");
ZX_ASSERT_MSG(shutdown_state_.completed,
"Caller destroying node without awaiting shutdown completion.");
}
NodeType ProcessNode::Type() const { return type_; }
void ProcessNode::Shutdown(fit::closure callback) {
TRACE_DURATION("camera", "ProcessNode::Shutdown", "this", this);
zxlogf(INFO, "ProcessNode::Shutdown(%s) - start", label_.c_str());
ZX_ASSERT_MSG(!shutdown_state_.requested, "Caller requested shutdown multiple times.");
auto nonce = TRACE_NONCE();
TRACE_FLOW_BEGIN("camera", "ProcessNode::Shutdown.shutdown", nonce);
shutdown_state_.requested = true;
ShutdownImpl([this, nonce, callback = std::move(callback)] {
TRACE_DURATION("camera", "ProcessNode::Shutdown.callback", "this", this);
TRACE_FLOW_END("camera", "ProcessNode::Shutdown.shutdown", nonce);
zxlogf(INFO, "ProcessNode::Shutdown(%s) - finish", label_.c_str());
ZX_ASSERT_MSG(shutdown_state_.requested, "Node sent unsolicited shutdown callback.");
ZX_ASSERT_MSG(!shutdown_state_.completed, "Node sent multiple shutdown callbacks.");
shutdown_state_.completed = true;
callback();
});
}
void ProcessNode::SetLabel(std::string label) {
zxlogf(INFO, "ProcessNode::SetLabel(%s) - start", label_.c_str());
label_ = std::move(label);
}
void ProcessNode::SendFrame(uint32_t index, frame_metadata_t metadata,
fit::closure release_callback) const {
TRACE_DURATION("camera", "ProcessNode::SendFrame", "this", this, "index", index);
ZX_ASSERT(metadata.timestamp > 0);
ZX_ASSERT(metadata.capture_timestamp > 0);
// If the node is shutting down, immediately release the frame.
if (shutdown_state_.requested) {
release_callback();
return;
}
// Wrap the node-provided callback in a trace flow.
auto nonce = TRACE_NONCE();
TRACE_FLOW_BEGIN("camera", "ProcessNode::SendFrame.release", nonce);
FrameToken token(index, [this, index, nonce, callback = std::move(release_callback)] {
TRACE_DURATION("camera", "ProcessNode::SendFrame.callback", "this", this, "index", index);
TRACE_FLOW_END("camera", "ProcessNode::SendFrame.release", nonce);
callback();
});
frame_callback_(std::move(token), metadata);
}
const fuchsia::sysmem2::BufferCollectionInfo& ProcessNode::InputBuffers() const {
ZX_ASSERT(attachments_.input_collection.has_value());
return attachments_.input_collection->get().buffers;
}
const std::vector<fuchsia::images2::ImageFormat>& ProcessNode::InputFormats() const {
ZX_ASSERT(attachments_.input_formats.has_value());
return attachments_.input_formats->get();
}
const fuchsia::sysmem2::BufferCollectionInfo& ProcessNode::OutputBuffers() const {
ZX_ASSERT(attachments_.output_collection.has_value());
return attachments_.output_collection->get().buffers;
}
const std::vector<fuchsia::images2::ImageFormat>& ProcessNode::OutputFormats() const {
ZX_ASSERT(attachments_.output_formats.has_value());
return attachments_.output_formats->get();
}
const hw_accel_frame_callback* ProcessNode::GetHwFrameReadyCallback(
cpp20::source_location location) {
hwaccel_callbacks_.frame_callsites.push_back(location);
return &hwaccel_callbacks_.frame;
}
const hw_accel_res_change_callback* ProcessNode::GetHwFrameResolutionChangeCallback(
cpp20::source_location location) {
hwaccel_callbacks_.res_change_callsites.push_back(location);
return &hwaccel_callbacks_.res_change;
}
const hw_accel_remove_task_callback* ProcessNode::GetHwTaskRemovedCallback(
cpp20::source_location location) {
hwaccel_callbacks_.remove_task_callsites.push_back(location);
return &hwaccel_callbacks_.remove_task;
}
void ProcessNode::PostTask(fit::closure task, cpp20::source_location location) {
auto nonce = TRACE_NONCE();
auto whence = Whence(location);
TRACE_DURATION("camera", "PostTask", "whence", whence);
TRACE_FLOW_BEGIN("camera", "ProcessNodePostTask", nonce);
async::PostTask(dispatcher_, [nonce, whence, task = std::move(task)] {
TRACE_DURATION("camera", "PostTask.task", "whence", whence);
TRACE_FLOW_END("camera", "ProcessNodePostTask", nonce);
task();
});
}
void ProcessNode::StaticHwFrameReady(void* ctx, const frame_available_info_t* info) {
auto node = static_cast<ProcessNode*>(ctx);
node->PostTask([node, info = *info] { node->HwFrameReady(info); });
}
void ProcessNode::StaticHwFrameResolutionChanged(void* ctx, const frame_available_info_t* info) {
auto node = static_cast<ProcessNode*>(ctx);
node->PostTask([node, info = *info] { node->HwFrameResolutionChanged(info); });
}
void ProcessNode::StaticHwTaskRemoved(void* ctx, task_remove_status_t status) {
auto node = static_cast<ProcessNode*>(ctx);
node->PostTask([node, status] { node->HwTaskRemoved(status); });
}
} // namespace camera