blob: b5c4e8007e37332e851ec8c5b84184fa4abfabed [file] [log] [blame]
// 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.
#ifndef GARNET_BIN_MEDIAPLAYER_GRAPH_MODELS_ASYNC_NODE_H_
#define GARNET_BIN_MEDIAPLAYER_GRAPH_MODELS_ASYNC_NODE_H_
#include "garnet/bin/mediaplayer/graph/models/node.h"
#include "garnet/bin/mediaplayer/graph/models/stage.h"
#include "garnet/bin/mediaplayer/graph/packet.h"
#include "garnet/bin/mediaplayer/graph/payloads/payload_allocator.h"
#include "garnet/bin/mediaplayer/graph/payloads/payload_config.h"
namespace media_player {
// TODO(dalesat): Ensure that we contractually have all the configuration
// info we need.
// TODO(dalesat): Track payload allocations and complain when usage exceeds
// expectations set by payload configurations.
// TODO(dalesat): Be more precise about the language around the semantics of
// payload configurations.
// Stage for |AsyncNode|.
class AsyncNodeStage : public Stage {
public:
using AllocateCallback =
fit::function<fbl::RefPtr<PayloadBuffer>(uint64_t, const PayloadVmos&)>;
~AsyncNodeStage() override {}
//////////////////////////////////////////////////////////////////////////////
// Methods relating to inputs (inbound packets from upstream).
//////////////////////////////////////////////////////////////////////////////
// Indicates that the specified input exists but explicityly defers its
// configuration until a later time. This call is provided so the stage is
// informed that the input exists, even though the node doesn't know enough
// at that point to configure the input completely. This allows the input to
// be connected up by whoever is building the graph. The connection won't
// transition to ready state (see |InputConnectionReady|) until the input is
// fully configured.
//
// This method must be called on the main graph thread.
virtual void ConfigureInputDeferred(size_t input_index = 0) = 0;
// Configures an input to address payloads as contiguous regions of process
// virtual memory. |max_aggregate_payload_size| sets expectations about how
// much memory will be required for all the payloads that the input will keep
// in memory at one time. This value does not include memory required by
// the connected output or for buffers queued on the connection. Likewise,
// |max_payload_count| sets expectations about how many payloads the input
// will keep in memory at one time. At least one of these two values must be
// non-zero.
//
// Calling this function prohibits the use of |UseInputVmos| or
// |ProvideInputVmos| for the specified input.
//
// Returns true if the connection is ready for allocation activity. Returns
// false if not, in which case |AsyncNode::InputConnectionReady| is called
// when the connection becomes ready.
//
// This method may be called on any thread provided the input has been
// configured previously (possibly with |ConfigureInputDeferred|). Otherwise,
// it must be called on the main graph thread.
virtual bool ConfigureInputToUseLocalMemory(
uint64_t max_aggregate_payload_size, uint32_t max_payload_count,
size_t input_index = 0) = 0;
// Configures an input to address payloads as contiguous regions in VMOs
// that are created by some other party. |max_aggregate_payload_size| sets
// expectations about how much memory will be required for the payloads that
// the input will keep in memory at one time. This value does not include
// memory required by the connected output or for buffers queued on the
// connection. Likewise, |max_payload_count| sets expectations about how many
// payloads the input will keep in memory at one time. |max_payload_size|
// sets expectations about how large payloads can be. Either or both of
// |max_aggregate_payload_size| and |max_payload_count| must be non-zero.
//
// |vmo_allocation| indicates how the payload buffers must be distributed
// across the VMOs. |physically_contiguous| indicates whether the VMOs
// must be physically contiguous. If and only if |physically_contiguous|
// is true, |bti_handle| provides the handle required for
// |zx_vmo_create_contiguous|.
//
// Calling this function prohibits the use of |ProvideInputVmos| for the
// specified input. |UseInputVmos| is available to determine what VMOs are
// being used.
//
// |allocate_callback| is used when the node wants to perform allocations
// against the VMOs itself rather than allowing the |VmoAllocator| to do
// it. This callback will be called on an arbitrary thread and may not
// call any methods on the stage. The VMOs the allocator callback must
// allocate from will be provided by the payload manager, not by the
// connected output. This guarantee is made so the input doesn't have to
// deal with the arbitrary VMOs provided by the output.
// TODO(dalesat): Be explicit about what the VMOs will actually be like.
//
// Returns true if the connection is ready for allocation activity.
// Returns false if not, in which case |AsyncNode::InputConnectionReady|
// is called when the connection becomes ready.
//
// This method may be called on any thread provided the input has been
// configured previously (possibly with |ConfigureInputDeferred|).
// Otherwise, it must be called on the main graph thread.
virtual bool ConfigureInputToUseVmos(
uint64_t max_aggregate_payload_size, uint32_t max_payload_count,
uint64_t max_payload_size, VmoAllocation vmo_allocation,
bool physically_contiguous = false, zx::handle bti_handle = zx::handle(),
AllocateCallback allocate_callback = nullptr, size_t input_index = 0) = 0;
// Configures an input to address payloads as contiguous regions in VMOs
// that the input provides. If the VMOs provided by the input are
// inadequate to hold all the payloads that are kept in memory at one time,
// the connection will adapt accordingly by creating a separate allocator
// for the output and doing copies. |vmo_allocation| indicates how the
// payload buffers will be distributed across the VMOs.
// |physically_contiguous| indicates whether the VMOs will be contiguous in
// physical memory.
//
// Calling this function allows the use of |ProvideInputVmos| for the
// specified input.
//
// |allocate_callback| is used when the node wants to perform allocations
// against the VMOs itself rather than allowing the |VmoAllocator| to do it.
// This callback will be called on an arbitrary thread and may not call any
// methods on the stage. The VMOs the allocator callback must allocate from
// will always be the same VMOs provided by the input.
//
// Returns true if the connection is ready for allocation activity. Returns
// false if not, in which case |AsyncNode::InputConnectionReady| is called
// when the connection becomes ready.
//
// This method may be called on any thread provided the input has been
// configured previously (possibly with |ConfigureInputDeferred|). Otherwise,
// it must be called on the main graph thread.
virtual bool ConfigureInputToProvideVmos(
VmoAllocation vmo_allocation, bool physically_contiguous = false,
AllocateCallback allocate_callback = nullptr, size_t input_index = 0) = 0;
// Returns true if the specified output is ready for calls to |UseInputVmos|
// or |ProvideInputVmos|.
//
// This method may be called on an arbitrary thread.
virtual bool InputConnectionReady(size_t input_index = 0) const = 0;
// Returns the |PayloadVmos| for the specified input. This method is only
// is only useable if |ConfigureInputToUseVmos| or
// |ConfigureInputToProvideVmos| has been called to configure the specified
// input, and the connection is ready.
//
// This method may be called on an arbitrary thread.
virtual const PayloadVmos& UseInputVmos(size_t input_index = 0) const = 0;
// Returns the |PayloadVmoProvision| for the specified input. This method is
// only useable if |ConfigureInputToProvideVmos| has been called to
// configure the specified input, and the connection is ready.
//
// This method may be called on an arbitrary thread.
virtual PayloadVmoProvision& ProvideInputVmos(size_t input_index = 0) = 0;
// Requests an input packet on the specified input. |input_index| must be
// less than the configured input count. This method may be called from
// |AsyncNode::PutInputPacket|.
//
// This method may be called on an arbitrary thread.
virtual void RequestInputPacket(size_t input_index = 0) = 0;
//////////////////////////////////////////////////////////////////////////////
// Methods relating to outputs (outbound packets to downstream).
//////////////////////////////////////////////////////////////////////////////
// Indicates that the specified output exists but explicityly defers its
// configuration until a later time. This call is provided so the stage is
// informed that the output exists, even though the node doesn't know enough
// at that point to configure the output completely. This allows the output
// to be connected up by whoever is building the graph. The connection won't
// transition to ready state (see |OutputConnectionReady|) until the output
// is fully configured.
//
// This method must be called on the main graph thread.
virtual void ConfigureOutputDeferred(size_t output_index = 0) = 0;
// Configures an output to address payloads as contiguous regions of process
// virtual memory allocated by another party. |max_aggregate_payload_size|
// sets expectations about how much memory will be required for the payloads
// the output will keep in memory and for the payloads queued on the
// connection. This value does not include memory required by the connected
// input. Likewise, |max_payload_count| sets expectations about how many
// payloads the output will keep in memory at one time plus the number of
// payloads that may be queued on the connection. |max_payload_size| indicates
// how large a single payload may be. Either or both of
// |max_aggregate_payload_size| and |max_payload_count| must be non-zero.
//
// Calling this function prohibits the use of |UseOutputVmos| or
// |ProvideOutputVmos| for the specified output. |AllocatePayloadBuffer|
// is available for allocating payloads.
//
// Returns true if the connection is ready for allocation activity. Returns
// false if not, in which case |AsyncNode::OutputConnectionReady| is called
// when the connection becomes ready.
//
// This method may be called on any thread provided the output has been
// configured previously (possibly with |ConfigureOutputDeferred|). Otherwise,
// it must be called on the main graph thread.
virtual bool ConfigureOutputToUseLocalMemory(
uint64_t max_aggregate_payload_size, uint32_t max_payload_count,
uint64_t max_payload_size, size_t output_index = 0) = 0;
// Configures an output to allocate its own payloads from local memory. It is
// assumed that the output can allocate as much memory as is required.
// TODO(dalesat): Consider committing to handle shortfalls by copying.
//
// Calling this function prohibits the use of |UseOutputVmos|,
// |ProvideOutputVmos| or |AllocatePayloadBuffer| for the specified output.
//
// Returns true if the connection is ready for allocation activity. Returns
// false if not, in which case |AsyncNode::OutputConnectionReady| is called
// when the connection becomes ready.
//
// This method may be called on any thread provided the output has been
// configured previously (possibly with |ConfigureOutputDeferred|). Otherwise,
// it must be called on the main graph thread.
virtual bool ConfigureOutputToProvideLocalMemory(size_t output_index = 0) = 0;
// Configures an output to address payloads as contiguous regions in VMOs
// that are created by some other party. |max_aggregate_payload_size|
// sets expectations about how much memory will be required for the payloads
// the output will keep in memory and for the payloads queued on the
// connection. This value does not include memory required by the connected
// input. Likewise, |max_payload_count| sets expectations about how many
// payloads the output will keep in memory at one time plus the number of
// payloads that may be queued on the connection. |max_payload_size| indicates
// how large a single payload may be. Either |max_aggregate_payload_size| or
// |max_payload_count| must be non-zero.
//
// |vmo_allocation| indicates how the payload buffers must be distributed
// across the VMOs. |physically_contiguous| indicates whether the VMOs must
// be physically contiguous. If and only if |physically_contiguous| is true,
// |bti_handle| provides the handle required for |zx_vmo_create_contiguous|.
//
// Calling this function prohibits the use of |ProvideOutputVmos| for the
// specified output. |UseOutputVmos| is available to determine what VMOs are
// being used, and |AllocatePayloadBuffer| is available for allocating
// payloads.
//
// Returns true if the connection is ready for allocation activity. Returns
// false if not, in which case |AsyncNode::OutputConnectionReady| is called
// when the connection becomes ready.
//
// This method may be called on any thread provided the output has been
// configured previously (possibly with |ConfigureOutputDeferred|). Otherwise,
// it must be called on the main graph thread.
virtual bool ConfigureOutputToUseVmos(uint64_t max_aggregate_payload_size,
uint32_t max_payload_count,
uint64_t max_payload_size,
VmoAllocation vmo_allocation,
bool physically_contiguous = false,
zx::handle bti_handle = zx::handle(),
size_t output_index = 0) = 0;
// Configures an output to address payloads as contiguous regions in VMOs
// that the output provides. If the VMOs provided by the output are
// inadequate to hold all the payloads that are kept in memory at one time,
// the connection will adapt accordingly by creating a separate allocator
// for the output and doing copies. |vmo_allocation| indicates how the
// payload buffers will be distributed across the VMOs.
// |physically_contiguous| indicates whether the VMOs will be contiguous in
// physical memory.
//
// Calling this function allows the use of |ProvideOutputVmos| for the
// specified output, and |AllocatePayloadBuffer| is available for allocating
// payloads.
//
// Returns true if the connection is ready for allocation activity. Returns
// false if not, in which case |AsyncNode::OutputConnectionReady| is called
// when the connection becomes ready.
//
// This method may be called on any thread provided the output has been
// configured previously (possibly with |ConfigureOutputDeferred|). Otherwise,
// it must be called on the main graph thread.
virtual bool ConfigureOutputToProvideVmos(VmoAllocation vmo_allocation,
bool physically_contiguous = false,
size_t output_index = 0) = 0;
// Returns true if the specified input is ready for calls to
// |AllocatePayloadBuffer|, |UseOutputVmos| or |ProvideOutputVmos|.
//
// This method may be called on an arbitrary thread.
virtual bool OutputConnectionReady(size_t output_index = 0) const = 0;
// Allocates a payload buffer for the specified output. This method
// is only useable if a ConfigureOutputFor* method other than
// |ConfigureOutputToProvideLocalMemory| has been called to configure the
// specified output, and the connection is ready.
//
// This method may be called on an arbitrary thread.
virtual fbl::RefPtr<PayloadBuffer> AllocatePayloadBuffer(
uint64_t size, size_t output_index = 0) = 0;
// Returns the |PayloadVmos| for the specified output. This method is only
// useable if |ConfigureOutputToUseVmos| or |ConfigureOutputToProvideVmos|
// has been called to configure the specified output, and the connection is
// ready.
//
// This method may be called on an arbitrary thread.
virtual const PayloadVmos& UseOutputVmos(size_t output_index = 0) const = 0;
// Returns the |PayloadVmoProvision| for the specified output. This
// method is only useable if |ConfigureOutputToProvideVmos| has been called
// to configure the specified output, and the connection is ready.
//
// This method may be called on an arbitrary thread.
virtual PayloadVmoProvision& ProvideOutputVmos(size_t output_index = 0) = 0;
// Supplies a packet to be sent downstream on the specified output.
//
// This method may be called on an arbitrary thread.
virtual void PutOutputPacket(PacketPtr packet, size_t output_index = 0) = 0;
};
// Node model for async nodes. This model is intended to replace all other
// async models.
// TODO(dalesat): Remove other async models.
class AsyncNode : public Node<AsyncNodeStage> {
public:
~AsyncNode() override {}
// Configures inputs and outputs for the node. When this method is called,
// the node calls ConfigureInputXxx/ConfigureOutputXxx methods on the stage
// for each input and output the node will support.
//
// This method will be called on the graph's thread.
//
// TODO(dalesat): Support dynamic reconfiguration.
virtual void ConfigureConnectors() = 0;
//////////////////////////////////////////////////////////////////////////////
// Methods relating to inputs (inbound packets from upstream).
//////////////////////////////////////////////////////////////////////////////
// Notifies that the connection for the specified input is ready for
// allocation activity. Note that this method is not called if the connection
// becomes ready as the result of a call to a ConfigureInputXxx method on
// the stage. In that case, the ConfigureInputXxx method returns true to
// indicate the connection is ready.
virtual void OnInputConnectionReady(size_t input_index) {}
// Flushes an input. |hold_frame| indicates whether a video renderer should
// hold and display the newest frame. The callback is used to indicate that
// the flush operation is complete. It may be called synchronously or on an
// arbitrary thread. The default implementation aborts.
//
// Flushing operations proceed downstream from a particular output until a
// sink (node with no outputs) is reached. When an input is flushed on a node
// that has outputs, the node in question can assume that all of its outputs
// will be flushed as well. Outputs may be flushed independently, so the
// converse it not true.
//
// This method will be called on the graph's thread.
virtual void FlushInput(bool hold_frame, size_t input_index,
fit::closure callback) {
FXL_CHECK(false) << "FlushInput not implemented.";
}
// Supplies the node with a packet that arrived on the specified input. This
// method may call |AsyncNodeStage::RequestInputPacket|. The default
// implementation aborts.
//
// This method will be called on the graph's thread.
virtual void PutInputPacket(PacketPtr packet, size_t input_index) {
FXL_CHECK(false) << "PutInputPacket not implemented.";
}
//////////////////////////////////////////////////////////////////////////////
// Methods relating to outputs (outbound packets to downstream).
//////////////////////////////////////////////////////////////////////////////
// Notifies that the connection for the specified output is ready for
// allocation activity. Note that this method is not called if the connection
// becomes ready as the result of a call to a ConfigureOutputXxx method on
// the stage. In that case, the ConfigureOutputXxx method returns true to
// indicate the connection is ready.
virtual void OnOutputConnectionReady(size_t output_index) {}
// Flushes an output. The callback is used to indicate that the flush
// operation is complete. It may be called synchronously or on an arbitrary
// thread. The default implementation aborts.
//
// Flushing operations proceed downstream from a particular output until a
// sink (node with no outputs) is reached. When an input is flushed on a node
// that has outputs, the node in question can assume that all of its outputs
// will be flushed as well. Outputs may be flushed independently, so the
// converse it not true.
//
// This method will be called on the graph's thread.
virtual void FlushOutput(size_t output_index, fit::closure callback) {
FXL_CHECK(false) << "FlushOutput not implemented.";
}
// Requests an output packet. The default implementation aborts.
//
// This method will be called on the graph's thread.
virtual void RequestOutputPacket() {
FXL_CHECK(false) << "RequestOutputPacket not implemented.";
}
};
class AsyncNodeStageImpl;
template <typename TNode>
struct NodeTraits<TNode, typename std::enable_if<
std::is_base_of<AsyncNode, TNode>::value>::type> {
using stage_impl_type = AsyncNodeStageImpl;
};
} // namespace media_player
#endif // GARNET_BIN_MEDIAPLAYER_GRAPH_MODELS_ASYNC_NODE_H_