| // 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 |