2014-10-21 16:51:07 +00:00
|
|
|
//============================================================================
|
|
|
|
// Copyright (c) Kitware, Inc.
|
|
|
|
// All rights reserved.
|
|
|
|
// See LICENSE.txt for details.
|
|
|
|
// This software is distributed WITHOUT ANY WARRANTY; without even
|
|
|
|
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
|
|
// PURPOSE. See the above copyright notice for more information.
|
|
|
|
//
|
2017-09-20 21:33:44 +00:00
|
|
|
// Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
|
2014-10-21 16:51:07 +00:00
|
|
|
// Copyright 2014 UT-Battelle, LLC.
|
2015-05-21 12:09:22 +00:00
|
|
|
// Copyright 2014 Los Alamos National Security.
|
2014-10-21 16:51:07 +00:00
|
|
|
//
|
2017-09-20 21:33:44 +00:00
|
|
|
// Under the terms of Contract DE-NA0003525 with NTESS,
|
2014-10-21 16:51:07 +00:00
|
|
|
// the U.S. Government retains certain rights in this software.
|
|
|
|
//
|
|
|
|
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
|
|
|
|
// Laboratory (LANL), the U.S. Government retains certain rights in
|
|
|
|
// this software.
|
|
|
|
//============================================================================
|
|
|
|
#ifndef vtk_m_worklet_internal_DispatcherBase_h
|
|
|
|
#define vtk_m_worklet_internal_DispatcherBase_h
|
|
|
|
|
2015-09-17 19:45:35 +00:00
|
|
|
#include <vtkm/StaticAssert.h>
|
|
|
|
|
2014-10-21 16:51:07 +00:00
|
|
|
#include <vtkm/internal/FunctionInterface.h>
|
|
|
|
#include <vtkm/internal/Invocation.h>
|
|
|
|
|
|
|
|
#include <vtkm/cont/DeviceAdapter.h>
|
2016-09-12 14:30:03 +00:00
|
|
|
|
2017-01-09 21:15:32 +00:00
|
|
|
#include <vtkm/cont/ErrorBadType.h>
|
2014-10-21 16:51:07 +00:00
|
|
|
|
2014-10-23 14:28:50 +00:00
|
|
|
#include <vtkm/cont/arg/ControlSignatureTagBase.h>
|
2014-10-21 16:51:07 +00:00
|
|
|
#include <vtkm/cont/arg/Transport.h>
|
2014-10-22 21:15:14 +00:00
|
|
|
#include <vtkm/cont/arg/TypeCheck.h>
|
2014-10-21 16:51:07 +00:00
|
|
|
#include <vtkm/cont/internal/DynamicTransform.h>
|
|
|
|
|
2014-10-23 14:28:50 +00:00
|
|
|
#include <vtkm/exec/arg/ExecutionSignatureTagBase.h>
|
2014-10-21 16:51:07 +00:00
|
|
|
|
2016-08-01 16:37:55 +00:00
|
|
|
#include <vtkm/internal/brigand.hpp>
|
2014-10-22 21:15:14 +00:00
|
|
|
|
|
|
|
#include <sstream>
|
2014-10-21 16:51:07 +00:00
|
|
|
|
2017-11-15 17:12:48 +00:00
|
|
|
namespace vtkm
|
|
|
|
{
|
|
|
|
namespace cont
|
|
|
|
{
|
|
|
|
|
|
|
|
// Forward declaration.
|
|
|
|
template <typename CellSetList>
|
|
|
|
class DynamicCellSetBase;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
namespace vtkm
|
|
|
|
{
|
|
|
|
namespace worklet
|
|
|
|
{
|
|
|
|
namespace internal
|
|
|
|
{
|
|
|
|
namespace detail
|
|
|
|
{
|
2014-10-21 16:51:07 +00:00
|
|
|
|
2015-07-17 12:49:43 +00:00
|
|
|
// This code is actually taking an error found at compile-time and not
|
|
|
|
// reporting it until run-time. This seems strange at first, but this
|
|
|
|
// behavior is actually important. With dynamic arrays and similar dynamic
|
|
|
|
// classes, there may be types that are technically possible (such as using a
|
|
|
|
// vector where a scalar is expected) but in reality never happen. Thus, for
|
|
|
|
// these unsupported combinations we just silently halt the compiler from
|
|
|
|
// attempting to create code for these errant conditions and throw a run-time
|
|
|
|
// error if one every tries to create one.
|
2017-11-15 17:12:48 +00:00
|
|
|
inline void PrintFailureMessage(int index)
|
2015-07-17 12:49:43 +00:00
|
|
|
{
|
|
|
|
std::stringstream message;
|
2017-05-18 14:29:41 +00:00
|
|
|
message << "Encountered bad type for parameter " << index
|
2015-07-17 12:49:43 +00:00
|
|
|
<< " when calling Invoke on a dispatcher.";
|
2017-01-09 21:15:32 +00:00
|
|
|
throw vtkm::cont::ErrorBadType(message.str());
|
2015-07-17 12:49:43 +00:00
|
|
|
}
|
|
|
|
|
2017-12-12 21:14:06 +00:00
|
|
|
template <typename T, bool noError>
|
|
|
|
struct ReportTypeOnError;
|
|
|
|
template <typename T>
|
|
|
|
struct ReportTypeOnError<T, true> : std::true_type
|
|
|
|
{
|
|
|
|
};
|
|
|
|
|
|
|
|
template <int Value, bool noError>
|
|
|
|
struct ReportValueOnError;
|
|
|
|
template <int Value>
|
|
|
|
struct ReportValueOnError<Value, true> : std::true_type
|
2017-11-15 17:12:48 +00:00
|
|
|
{
|
|
|
|
};
|
|
|
|
|
2016-08-01 16:37:55 +00:00
|
|
|
// Is designed as a brigand fold operation.
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, typename State>
|
2015-10-23 20:27:49 +00:00
|
|
|
struct DetermineIfHasDynamicParameter
|
|
|
|
{
|
2016-08-01 16:37:55 +00:00
|
|
|
using DynamicTag = typename vtkm::cont::internal::DynamicTransformTraits<T>::DynamicTag;
|
2017-05-18 14:29:41 +00:00
|
|
|
using isDynamic =
|
|
|
|
typename std::is_same<DynamicTag, vtkm::cont::internal::DynamicTransformTagCastAndCall>::type;
|
2015-10-23 20:27:49 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
using type = std::integral_constant<bool, (State::value || isDynamic::value)>;
|
2015-10-23 20:27:49 +00:00
|
|
|
};
|
|
|
|
|
2017-11-15 17:12:48 +00:00
|
|
|
|
2016-08-01 16:37:55 +00:00
|
|
|
// Is designed as a brigand fold operation.
|
2017-12-12 21:14:06 +00:00
|
|
|
template <typename WorkletType>
|
|
|
|
struct DetermineHasCorrectParameters
|
2015-10-26 20:35:02 +00:00
|
|
|
{
|
2017-12-12 21:14:06 +00:00
|
|
|
template <typename T, typename State, typename SigTypes>
|
|
|
|
struct Functor
|
|
|
|
{
|
|
|
|
//T is the type of the Param at the current index
|
|
|
|
//State if the index to use to fetch the control signature tag
|
|
|
|
using ControlSignatureTag = typename brigand::at_c<SigTypes, State::value>;
|
|
|
|
using TypeCheckTag = typename ControlSignatureTag::TypeCheckTag;
|
|
|
|
|
|
|
|
static VTKM_CONSTEXPR bool isCorrect = vtkm::cont::arg::TypeCheck<TypeCheckTag, T>::value;
|
|
|
|
|
|
|
|
// If you get an error on the line below, that means that your code has called the
|
|
|
|
// Invoke method on a dispatcher, and one of the arguments of the Invoke is the wrong
|
|
|
|
// type. Each argument of Invoke corresponds to a tag in the arguments of the
|
|
|
|
// ControlSignature of the worklet. If there is a mismatch, then you get an error here
|
|
|
|
// (instead of where you called the dispatcher). For example, if the worklet has a
|
|
|
|
// control signature as ControlSignature(CellSetIn, ...) and the first argument passed
|
|
|
|
// to Invoke is an ArrayHandle, you will get an error here because you cannot use an
|
|
|
|
// ArrayHandle in place of a CellSetIn argument. (You need to use a CellSet.) See a few
|
|
|
|
// lines later for some diagnostics to help you trace where the error occured.
|
2017-12-12 21:46:10 +00:00
|
|
|
VTKM_READ_THE_SOURCE_CODE_FOR_HELP(isCorrect);
|
2017-12-12 21:14:06 +00:00
|
|
|
|
|
|
|
// If you are getting the error described above, the following lines will give you some
|
|
|
|
// diagnostics (in the form of compile errors). Each one will result in a compile error
|
|
|
|
// reporting an undefined type for ReportTypeOnError (or ReportValueOnError). What we are
|
|
|
|
// really reporting is the first template argument, which is one of the types or values that
|
|
|
|
// should help pinpoint where the error is. The comment for static_assert provides the
|
|
|
|
// type/value being reported. (Note that some compilers report better types than others. If
|
|
|
|
// your compiler is giving unhelpful types like "T" or "WorkletType", you may need to try a
|
|
|
|
// different compiler.)
|
|
|
|
static_assert(ReportTypeOnError<T, isCorrect>::value, "Type passed to Invoke");
|
|
|
|
static_assert(ReportTypeOnError<WorkletType, isCorrect>::value, "Worklet being invoked.");
|
|
|
|
static_assert(ReportValueOnError<State::value, isCorrect>::value, "Index of Invoke parameter");
|
|
|
|
static_assert(ReportTypeOnError<TypeCheckTag, isCorrect>::value, "Type check tag used");
|
|
|
|
|
|
|
|
// This final static_assert gives a human-readable error message. Ideally, this would be
|
|
|
|
// placed first, but some compilers will suppress further errors when a static_assert
|
|
|
|
// fails, so you would not see the other diagnostic error messages.
|
|
|
|
static_assert(isCorrect,
|
|
|
|
"The type of one of the arguments to the dispatcher's Invoke method is "
|
|
|
|
"incompatible with the corresponding tag in the worklet's ControlSignature.");
|
|
|
|
|
|
|
|
using type = std::integral_constant<std::size_t, State::value + 1>;
|
|
|
|
};
|
2015-10-26 20:35:02 +00:00
|
|
|
};
|
|
|
|
|
2014-10-23 14:28:50 +00:00
|
|
|
// Checks that an argument in a ControlSignature is a valid control signature
|
|
|
|
// tag. Causes a compile error otherwise.
|
|
|
|
struct DispatcherBaseControlSignatureTagCheck
|
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename ControlSignatureTag, vtkm::IdComponent Index>
|
|
|
|
struct ReturnType
|
|
|
|
{
|
2014-10-23 14:28:50 +00:00
|
|
|
// If you get a compile error here, it means there is something that is
|
|
|
|
// not a valid control signature tag in a worklet's ControlSignature.
|
|
|
|
VTKM_IS_CONTROL_SIGNATURE_TAG(ControlSignatureTag);
|
|
|
|
typedef ControlSignatureTag type;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
// Checks that an argument in a ExecutionSignature is a valid execution
|
|
|
|
// signature tag. Causes a compile error otherwise.
|
|
|
|
struct DispatcherBaseExecutionSignatureTagCheck
|
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename ExecutionSignatureTag, vtkm::IdComponent Index>
|
|
|
|
struct ReturnType
|
|
|
|
{
|
2014-10-23 14:28:50 +00:00
|
|
|
// If you get a compile error here, it means there is something that is not
|
|
|
|
// a valid execution signature tag in a worklet's ExecutionSignature.
|
|
|
|
VTKM_IS_EXECUTION_SIGNATURE_TAG(ExecutionSignatureTag);
|
|
|
|
typedef ExecutionSignatureTag type;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2015-10-21 21:20:27 +00:00
|
|
|
// A look up helper used by DispatcherBaseTransportFunctor to determine
|
|
|
|
//the types independent of the device we are templated on.
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename ControlInterface, vtkm::IdComponent Index>
|
2015-10-21 21:20:27 +00:00
|
|
|
struct DispatcherBaseTransportInvokeTypes
|
|
|
|
{
|
|
|
|
//Moved out of DispatcherBaseTransportFunctor to reduce code generation
|
2017-05-18 14:29:41 +00:00
|
|
|
typedef typename ControlInterface::template ParameterType<Index>::type ControlSignatureTag;
|
2015-10-21 21:20:27 +00:00
|
|
|
typedef typename ControlSignatureTag::TransportTag TransportTag;
|
|
|
|
};
|
|
|
|
|
2017-03-24 20:51:46 +00:00
|
|
|
VTKM_CONT
|
2017-05-18 14:29:41 +00:00
|
|
|
inline vtkm::Id FlatRange(vtkm::Id range)
|
2017-03-24 20:51:46 +00:00
|
|
|
{
|
|
|
|
return range;
|
|
|
|
}
|
|
|
|
|
|
|
|
VTKM_CONT
|
2017-05-18 14:29:41 +00:00
|
|
|
inline vtkm::Id FlatRange(const vtkm::Id3& range)
|
2017-03-24 20:51:46 +00:00
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
return range[0] * range[1] * range[2];
|
2017-03-24 20:51:46 +00:00
|
|
|
}
|
|
|
|
|
2014-10-23 14:28:50 +00:00
|
|
|
// A functor used in a StaticCast of a FunctionInterface to transport arguments
|
|
|
|
// from the control environment to the execution environment.
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename ControlInterface, typename InputDomainType, typename Device>
|
2014-10-21 16:51:07 +00:00
|
|
|
struct DispatcherBaseTransportFunctor
|
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
const InputDomainType& InputDomain; // Warning: this is a reference
|
2017-03-24 20:51:46 +00:00
|
|
|
vtkm::Id InputRange;
|
|
|
|
vtkm::Id OutputRange;
|
2014-10-21 16:51:07 +00:00
|
|
|
|
2015-05-05 14:46:23 +00:00
|
|
|
// TODO: We need to think harder about how scheduling on 3D arrays works.
|
|
|
|
// Chances are we need to allow the transport for each argument to manage
|
|
|
|
// 3D indices (for example, allocate a 3D array instead of a 1D array).
|
|
|
|
// But for now, just treat all transports as 1D arrays.
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename InputRangeType, typename OutputRangeType>
|
|
|
|
VTKM_CONT DispatcherBaseTransportFunctor(const InputDomainType& inputDomain,
|
|
|
|
const InputRangeType& inputRange,
|
|
|
|
const OutputRangeType& outputRange)
|
|
|
|
: InputDomain(inputDomain)
|
|
|
|
, InputRange(FlatRange(inputRange))
|
|
|
|
, OutputRange(FlatRange(outputRange))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename ControlParameter, vtkm::IdComponent Index>
|
|
|
|
struct ReturnType
|
|
|
|
{
|
|
|
|
using TransportTag =
|
|
|
|
typename DispatcherBaseTransportInvokeTypes<ControlInterface, Index>::TransportTag;
|
|
|
|
using TransportType =
|
|
|
|
typename vtkm::cont::arg::Transport<TransportTag, ControlParameter, Device>;
|
2016-12-19 22:41:00 +00:00
|
|
|
using type = typename TransportType::ExecObjectType;
|
2014-10-21 16:51:07 +00:00
|
|
|
};
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename ControlParameter, vtkm::IdComponent Index>
|
|
|
|
VTKM_CONT typename ReturnType<ControlParameter, Index>::type operator()(
|
2017-05-26 17:53:28 +00:00
|
|
|
const ControlParameter& invokeData,
|
|
|
|
vtkm::internal::IndexTag<Index>) const
|
2015-10-21 21:20:27 +00:00
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
using TransportTag =
|
|
|
|
typename DispatcherBaseTransportInvokeTypes<ControlInterface, Index>::TransportTag;
|
|
|
|
vtkm::cont::arg::Transport<TransportTag, ControlParameter, Device> transport;
|
|
|
|
return transport(invokeData, this->InputDomain, this->InputRange, this->OutputRange);
|
2014-10-21 16:51:07 +00:00
|
|
|
}
|
2017-01-10 18:10:38 +00:00
|
|
|
|
|
|
|
private:
|
2017-05-18 14:29:41 +00:00
|
|
|
void operator=(const DispatcherBaseTransportFunctor&) = delete;
|
2014-10-21 16:51:07 +00:00
|
|
|
};
|
|
|
|
|
2017-11-15 17:12:48 +00:00
|
|
|
//forward declares
|
2017-12-06 18:57:05 +00:00
|
|
|
template <std::size_t LeftToProcess>
|
2017-11-15 17:12:48 +00:00
|
|
|
struct for_each_dynamic_arg;
|
|
|
|
|
2017-12-06 18:57:05 +00:00
|
|
|
template <std::size_t LeftToProcess, typename TypeCheckTag>
|
2017-11-15 17:12:48 +00:00
|
|
|
struct convert_arg_wrapper
|
|
|
|
{
|
|
|
|
template <typename T, typename... Args>
|
|
|
|
void operator()(T&& t, Args&&... args) const
|
|
|
|
{
|
|
|
|
using Type = typename std::decay<T>::type;
|
|
|
|
using valid =
|
|
|
|
std::integral_constant<bool, vtkm::cont::arg::TypeCheck<TypeCheckTag, Type>::value>;
|
|
|
|
this->WillContinue(valid(), std::forward<T>(t), std::forward<Args>(args)...);
|
|
|
|
}
|
|
|
|
template <typename T, typename... Args>
|
|
|
|
void WillContinue(std::true_type, T&& t, Args&&... args) const
|
|
|
|
{
|
|
|
|
for_each_dynamic_arg<LeftToProcess - 1>()(std::forward<Args>(args)..., std::forward<T>(t));
|
|
|
|
}
|
|
|
|
template <typename... Args>
|
|
|
|
void WillContinue(std::false_type, Args&&...) const
|
|
|
|
{
|
|
|
|
vtkm::worklet::internal::detail::PrintFailureMessage(LeftToProcess);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-12-06 18:57:05 +00:00
|
|
|
template <std::size_t LeftToProcess,
|
|
|
|
typename T,
|
|
|
|
typename ContParams,
|
|
|
|
typename Trampoline,
|
|
|
|
typename... Args>
|
2017-11-15 17:12:48 +00:00
|
|
|
inline void convert_arg(vtkm::cont::internal::DynamicTransformTagStatic,
|
|
|
|
T&& t,
|
|
|
|
const ContParams&,
|
|
|
|
const Trampoline& trampoline,
|
|
|
|
Args&&... args)
|
|
|
|
{ //This is a static array, so just push it to the back
|
|
|
|
using popped_sig = brigand::pop_front<ContParams>;
|
|
|
|
for_each_dynamic_arg<LeftToProcess - 1>()(
|
|
|
|
trampoline, popped_sig(), std::forward<Args>(args)..., std::forward<T>(t));
|
|
|
|
}
|
|
|
|
|
2017-12-06 18:57:05 +00:00
|
|
|
template <std::size_t LeftToProcess,
|
|
|
|
typename T,
|
|
|
|
typename ContParams,
|
|
|
|
typename Trampoline,
|
|
|
|
typename... Args>
|
2017-11-15 17:12:48 +00:00
|
|
|
inline void convert_arg(vtkm::cont::internal::DynamicTransformTagCastAndCall,
|
|
|
|
T&& t,
|
|
|
|
const ContParams&,
|
|
|
|
const Trampoline& trampoline,
|
|
|
|
Args&&... args)
|
|
|
|
{ //This is something dynamic so cast and call
|
|
|
|
using tag_check = typename brigand::at_c<ContParams, 0>::TypeCheckTag;
|
|
|
|
using popped_sig = brigand::pop_front<ContParams>;
|
|
|
|
|
|
|
|
vtkm::cont::CastAndCall(t,
|
|
|
|
convert_arg_wrapper<LeftToProcess, tag_check>(),
|
|
|
|
trampoline,
|
|
|
|
popped_sig(),
|
|
|
|
std::forward<Args>(args)...);
|
|
|
|
}
|
|
|
|
|
2017-12-06 18:57:05 +00:00
|
|
|
template <std::size_t LeftToProcess>
|
2017-11-15 17:12:48 +00:00
|
|
|
struct for_each_dynamic_arg
|
|
|
|
{
|
|
|
|
template <typename Trampoline, typename ContParams, typename T, typename... Args>
|
|
|
|
void operator()(const Trampoline& trampoline, ContParams&& sig, T&& t, Args&&... args) const
|
|
|
|
{
|
|
|
|
//Determine that state of T
|
|
|
|
using Type = typename std::decay<T>::type;
|
|
|
|
using tag = typename vtkm::cont::internal::DynamicTransformTraits<Type>::DynamicTag;
|
|
|
|
//convert the first item to a known type
|
|
|
|
convert_arg<LeftToProcess>(
|
|
|
|
tag(), std::forward<T>(t), sig, trampoline, std::forward<Args>(args)...);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <>
|
|
|
|
struct for_each_dynamic_arg<0>
|
|
|
|
{
|
|
|
|
template <typename Trampoline, typename ContParams, typename... Args>
|
|
|
|
void operator()(const Trampoline& trampoline, ContParams&&, Args&&... args) const
|
|
|
|
{
|
|
|
|
trampoline.StartInvokeDynamic(std::false_type(), std::forward<Args>(args)...);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename Trampoline, typename ContParams, typename... Args>
|
|
|
|
inline void deduce(Trampoline&& trampoline, ContParams&& sig, Args&&... args)
|
|
|
|
{
|
|
|
|
for_each_dynamic_arg<sizeof...(Args)>()(std::forward<Trampoline>(trampoline), sig, args...);
|
|
|
|
}
|
|
|
|
|
2014-10-21 16:51:07 +00:00
|
|
|
} // namespace detail
|
|
|
|
|
|
|
|
/// Base class for all dispatcher classes. Every worklet type should have its
|
|
|
|
/// own dispatcher.
|
|
|
|
///
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename DerivedClass, typename WorkletType, typename BaseWorkletType>
|
2014-10-21 16:51:07 +00:00
|
|
|
class DispatcherBase
|
|
|
|
{
|
|
|
|
private:
|
2017-05-18 14:29:41 +00:00
|
|
|
typedef DispatcherBase<DerivedClass, WorkletType, BaseWorkletType> MyType;
|
2014-10-21 16:51:07 +00:00
|
|
|
|
2017-11-15 17:12:48 +00:00
|
|
|
friend struct detail::for_each_dynamic_arg<0>;
|
2014-10-21 16:51:07 +00:00
|
|
|
|
|
|
|
protected:
|
2017-05-18 14:29:41 +00:00
|
|
|
typedef vtkm::internal::FunctionInterface<typename WorkletType::ControlSignature>
|
|
|
|
ControlInterface;
|
|
|
|
typedef vtkm::internal::FunctionInterface<typename WorkletType::ExecutionSignature>
|
|
|
|
ExecutionInterface;
|
2014-10-21 16:51:07 +00:00
|
|
|
|
|
|
|
static const vtkm::IdComponent NUM_INVOKE_PARAMS = ControlInterface::ARITY;
|
|
|
|
|
2014-10-23 14:28:50 +00:00
|
|
|
private:
|
|
|
|
// We don't really need these types, but declaring them checks the arguments
|
|
|
|
// of the control and execution signatures.
|
2017-05-18 14:29:41 +00:00
|
|
|
typedef typename ControlInterface::template StaticTransformType<
|
|
|
|
detail::DispatcherBaseControlSignatureTagCheck>::type ControlSignatureCheck;
|
|
|
|
typedef typename ExecutionInterface::template StaticTransformType<
|
|
|
|
detail::DispatcherBaseExecutionSignatureTagCheck>::type ExecutionSignatureCheck;
|
|
|
|
|
2017-11-15 17:12:48 +00:00
|
|
|
template <typename... Args>
|
|
|
|
VTKM_CONT void StartInvoke(Args&&... args) const
|
2014-10-21 16:51:07 +00:00
|
|
|
{
|
2017-11-15 17:12:48 +00:00
|
|
|
using ParameterInterface =
|
|
|
|
vtkm::internal::FunctionInterface<void(typename std::decay<Args>::type...)>;
|
2016-08-29 15:13:00 +00:00
|
|
|
|
2015-09-17 19:45:35 +00:00
|
|
|
VTKM_STATIC_ASSERT_MSG(ParameterInterface::ARITY == NUM_INVOKE_PARAMS,
|
|
|
|
"Dispatcher Invoke called with wrong number of arguments.");
|
2015-09-17 05:34:49 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
static_assert(
|
|
|
|
std::is_base_of<BaseWorkletType, WorkletType>::value,
|
2016-08-29 15:13:00 +00:00
|
|
|
"The worklet being scheduled by this dispatcher doesn't match the type of the dispatcher");
|
2014-10-21 16:51:07 +00:00
|
|
|
|
2015-10-23 20:27:49 +00:00
|
|
|
//We need to determine if we have the need to do any dynamic
|
|
|
|
//transforms. This is fairly simple of a query. We just need to check
|
|
|
|
//everything in the FunctionInterface and see if any of them have the
|
|
|
|
//proper dynamic trait. Doing this, allows us to generate zero dynamic
|
|
|
|
//check & convert code when we already know all the types. This results
|
|
|
|
//in smaller executables and libraries.
|
2016-08-01 16:37:55 +00:00
|
|
|
using ParamTypes = typename ParameterInterface::ParameterSig;
|
|
|
|
using HasDynamicTypes =
|
2017-05-26 17:53:28 +00:00
|
|
|
brigand::fold<ParamTypes,
|
|
|
|
std::false_type,
|
2017-05-18 14:29:41 +00:00
|
|
|
detail::DetermineIfHasDynamicParameter<brigand::_element, brigand::_state>>;
|
2015-10-23 20:27:49 +00:00
|
|
|
|
2017-11-15 17:12:48 +00:00
|
|
|
this->StartInvokeDynamic(HasDynamicTypes(), std::forward<Args>(args)...);
|
2017-05-18 14:29:41 +00:00
|
|
|
}
|
2015-10-23 20:27:49 +00:00
|
|
|
|
2017-11-15 17:12:48 +00:00
|
|
|
template <typename... Args>
|
|
|
|
VTKM_CONT void StartInvokeDynamic(std::true_type, Args&&... args) const
|
2015-10-23 20:27:49 +00:00
|
|
|
{
|
2014-10-22 21:15:14 +00:00
|
|
|
// As we do the dynamic transform, we are also going to check the static
|
|
|
|
// type against the TypeCheckTag in the ControlSignature tags. To do this,
|
|
|
|
// the check needs access to both the parameter (in the parameters
|
|
|
|
// argument) and the ControlSignature tags (in the ControlInterface type).
|
2017-11-15 17:12:48 +00:00
|
|
|
using ContParamsInfo =
|
|
|
|
vtkm::internal::detail::FunctionSigInfo<typename WorkletType::ControlSignature>;
|
|
|
|
detail::deduce(*this, typename ContParamsInfo::Parameters(), std::forward<Args>(args)...);
|
2014-10-21 16:51:07 +00:00
|
|
|
}
|
|
|
|
|
2017-11-15 17:12:48 +00:00
|
|
|
template <typename... Args>
|
|
|
|
VTKM_CONT void StartInvokeDynamic(std::false_type, Args&&... args) const
|
2015-10-23 20:27:49 +00:00
|
|
|
{
|
2017-11-15 17:12:48 +00:00
|
|
|
using ParameterInterface =
|
|
|
|
vtkm::internal::FunctionInterface<void(typename std::decay<Args>::type...)>;
|
2016-08-01 16:37:55 +00:00
|
|
|
|
2015-10-23 20:27:49 +00:00
|
|
|
//Nothing requires a conversion from dynamic to static types, so
|
2015-10-26 20:35:02 +00:00
|
|
|
//next we need to verify that each argument's type is correct. If not
|
|
|
|
//we need to throw a nice compile time error
|
2016-08-01 16:37:55 +00:00
|
|
|
using ParamTypes = typename ParameterInterface::ParameterSig;
|
|
|
|
using ContSigTypes = typename vtkm::internal::detail::FunctionSigInfo<
|
2017-05-18 14:29:41 +00:00
|
|
|
typename WorkletType::ControlSignature>::Parameters;
|
2015-10-23 20:27:49 +00:00
|
|
|
|
2017-11-15 17:12:48 +00:00
|
|
|
//isAllValid will throw a compile error if everything doesn't match
|
2017-12-12 21:14:06 +00:00
|
|
|
using isAllValid = brigand::fold<
|
|
|
|
ParamTypes,
|
|
|
|
std::integral_constant<std::size_t, 0>,
|
|
|
|
typename detail::DetermineHasCorrectParameters<WorkletType>::
|
|
|
|
template Functor<brigand::_element, brigand::_state, brigand::pin<ContSigTypes>>>;
|
2017-11-15 17:12:48 +00:00
|
|
|
|
|
|
|
//this warning exists so that we don't get a warning from not using isAllValid
|
|
|
|
using expectedLen = std::integral_constant<std::size_t, sizeof...(Args)>;
|
|
|
|
static_assert(isAllValid::value == expectedLen::value,
|
|
|
|
"All arguments failed the TypeCheck pass");
|
|
|
|
|
2017-12-28 21:41:13 +00:00
|
|
|
#if defined __NVCC__
|
|
|
|
// Disable warning "calling a __host__ function from a __host__ __device__"
|
|
|
|
// In some cases nv_exec_check_disable doesn't work and therefore you need
|
|
|
|
// to use the following suppressions
|
|
|
|
// This have been found by eigen:
|
|
|
|
// https://github.com/RLovelett/eigen/blame/master/Eigen/src/Core/util/DisableStupidWarnings.h
|
2018-01-09 15:54:24 +00:00
|
|
|
// To discover new dia_supress values use -Xcudafe "--display_error_number"
|
2017-12-28 21:41:13 +00:00
|
|
|
#pragma push
|
|
|
|
#pragma diag_suppress 2737
|
|
|
|
#pragma diag_suppress 2739
|
2018-01-09 15:54:24 +00:00
|
|
|
#pragma diag_suppress 2828
|
2017-12-28 21:41:13 +00:00
|
|
|
#endif
|
2017-11-15 17:12:48 +00:00
|
|
|
auto fi =
|
|
|
|
vtkm::internal::make_FunctionInterface<void, typename std::decay<Args>::type...>(args...);
|
2017-12-28 21:41:13 +00:00
|
|
|
#if defined __NVCC__
|
|
|
|
#pragma pop
|
|
|
|
#endif
|
|
|
|
|
2017-11-15 17:12:48 +00:00
|
|
|
auto ivc = vtkm::internal::Invocation<ParameterInterface,
|
|
|
|
ControlInterface,
|
|
|
|
ExecutionInterface,
|
|
|
|
WorkletType::InputDomain::INDEX,
|
|
|
|
vtkm::internal::NullType,
|
|
|
|
vtkm::internal::NullType>(
|
|
|
|
fi, vtkm::internal::NullType{}, vtkm::internal::NullType{});
|
|
|
|
static_cast<const DerivedClass*>(this)->DoInvoke(ivc);
|
2015-10-26 20:35:02 +00:00
|
|
|
}
|
|
|
|
|
2014-10-21 16:51:07 +00:00
|
|
|
public:
|
2017-11-15 17:12:48 +00:00
|
|
|
template <typename... Args>
|
|
|
|
VTKM_CONT void Invoke(Args&&... args) const
|
2016-09-01 14:41:45 +00:00
|
|
|
{
|
2017-11-15 17:12:48 +00:00
|
|
|
this->StartInvoke(std::forward<Args>(args)...);
|
2016-09-01 14:41:45 +00:00
|
|
|
}
|
2014-10-21 16:51:07 +00:00
|
|
|
|
|
|
|
protected:
|
2016-10-19 22:42:58 +00:00
|
|
|
VTKM_CONT
|
2017-05-18 14:29:41 +00:00
|
|
|
DispatcherBase(const WorkletType& worklet)
|
|
|
|
: Worklet(worklet)
|
|
|
|
{
|
|
|
|
}
|
2014-10-21 16:51:07 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename Invocation, typename DeviceAdapter>
|
2017-05-26 17:53:28 +00:00
|
|
|
VTKM_CONT void BasicInvoke(const Invocation& invocation,
|
|
|
|
vtkm::Id numInstances,
|
2017-05-18 14:29:41 +00:00
|
|
|
DeviceAdapter device) const
|
2014-10-21 16:51:07 +00:00
|
|
|
{
|
2015-09-24 22:38:42 +00:00
|
|
|
this->InvokeTransportParameters(
|
2017-05-18 14:29:41 +00:00
|
|
|
invocation, numInstances, this->Worklet.GetScatter().GetOutputRange(numInstances), device);
|
2014-10-21 16:51:07 +00:00
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename Invocation, typename DeviceAdapter>
|
2017-05-26 17:53:28 +00:00
|
|
|
VTKM_CONT void BasicInvoke(const Invocation& invocation,
|
|
|
|
vtkm::Id2 dimensions,
|
2017-05-18 14:29:41 +00:00
|
|
|
DeviceAdapter device) const
|
2015-06-22 13:07:27 +00:00
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
this->BasicInvoke(invocation, vtkm::Id3(dimensions[0], dimensions[1], 1), device);
|
2015-06-22 13:07:27 +00:00
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename Invocation, typename DeviceAdapter>
|
2017-05-26 17:53:28 +00:00
|
|
|
VTKM_CONT void BasicInvoke(const Invocation& invocation,
|
|
|
|
vtkm::Id3 dimensions,
|
2017-05-18 14:29:41 +00:00
|
|
|
DeviceAdapter device) const
|
2015-05-05 14:46:23 +00:00
|
|
|
{
|
2017-05-26 17:53:28 +00:00
|
|
|
this->InvokeTransportParameters(
|
|
|
|
invocation, dimensions, this->Worklet.GetScatter().GetOutputRange(dimensions), device);
|
2015-05-05 14:46:23 +00:00
|
|
|
}
|
|
|
|
|
2014-10-21 16:51:07 +00:00
|
|
|
WorkletType Worklet;
|
|
|
|
|
|
|
|
private:
|
2017-02-23 17:12:38 +00:00
|
|
|
// Dispatchers cannot be copied
|
2017-05-18 14:29:41 +00:00
|
|
|
DispatcherBase(const MyType&) = delete;
|
|
|
|
void operator=(const MyType&) = delete;
|
|
|
|
|
2017-05-26 17:53:28 +00:00
|
|
|
template <typename Invocation,
|
|
|
|
typename InputRangeType,
|
|
|
|
typename OutputRangeType,
|
2017-05-18 14:29:41 +00:00
|
|
|
typename DeviceAdapter>
|
|
|
|
VTKM_CONT void InvokeTransportParameters(const Invocation& invocation,
|
|
|
|
const InputRangeType& inputRange,
|
2017-07-11 12:33:56 +00:00
|
|
|
OutputRangeType&& outputRange,
|
2017-05-18 14:29:41 +00:00
|
|
|
DeviceAdapter device) const
|
2014-10-21 16:51:07 +00:00
|
|
|
{
|
2015-01-14 01:26:13 +00:00
|
|
|
// The first step in invoking a worklet is to transport the arguments to
|
|
|
|
// the execution environment. The invocation object passed to this function
|
2014-10-21 16:51:07 +00:00
|
|
|
// contains the parameters passed to Invoke in the control environment. We
|
|
|
|
// will use the template magic in the FunctionInterface class to invoke the
|
2015-01-14 01:26:13 +00:00
|
|
|
// appropriate Transport class on each parameter and get a list of
|
|
|
|
// execution objects (corresponding to the arguments of the Invoke in the
|
|
|
|
// control environment) in a FunctionInterface. Specifically, we use a
|
|
|
|
// static transform of the FunctionInterface to call the transport on each
|
|
|
|
// argument and return the corresponding execution environment object.
|
|
|
|
typedef typename Invocation::ParameterInterface ParameterInterfaceType;
|
2017-05-18 14:29:41 +00:00
|
|
|
const ParameterInterfaceType& parameters = invocation.Parameters;
|
2015-01-14 01:26:13 +00:00
|
|
|
|
2017-05-26 17:53:28 +00:00
|
|
|
typedef detail::DispatcherBaseTransportFunctor<typename Invocation::ControlInterface,
|
|
|
|
typename Invocation::InputDomainType,
|
|
|
|
DeviceAdapter>
|
2017-05-18 14:29:41 +00:00
|
|
|
TransportFunctorType;
|
|
|
|
typedef
|
|
|
|
typename ParameterInterfaceType::template StaticTransformType<TransportFunctorType>::type
|
|
|
|
ExecObjectParameters;
|
|
|
|
|
|
|
|
ExecObjectParameters execObjectParameters = parameters.StaticTransformCont(
|
|
|
|
TransportFunctorType(invocation.GetInputDomain(), inputRange, outputRange));
|
2014-10-21 16:51:07 +00:00
|
|
|
|
2015-09-22 04:35:13 +00:00
|
|
|
// Get the arrays used for scattering input to output.
|
|
|
|
typename WorkletType::ScatterType::OutputToInputMapType outputToInputMap =
|
2017-05-18 14:29:41 +00:00
|
|
|
this->Worklet.GetScatter().GetOutputToInputMap(inputRange);
|
2015-09-22 04:35:13 +00:00
|
|
|
typename WorkletType::ScatterType::VisitArrayType visitArray =
|
2017-05-18 14:29:41 +00:00
|
|
|
this->Worklet.GetScatter().GetVisitArray(inputRange);
|
2015-09-22 04:35:13 +00:00
|
|
|
|
2014-10-21 16:51:07 +00:00
|
|
|
// Replace the parameters in the invocation with the execution object and
|
2015-09-22 04:35:13 +00:00
|
|
|
// pass to next step of Invoke. Also add the scatter information.
|
2017-05-18 14:29:41 +00:00
|
|
|
this->InvokeSchedule(invocation.ChangeParameters(execObjectParameters)
|
|
|
|
.ChangeOutputToInputMap(outputToInputMap.PrepareForInput(device))
|
|
|
|
.ChangeVisitArray(visitArray.PrepareForInput(device)),
|
2017-05-26 17:53:28 +00:00
|
|
|
outputRange,
|
|
|
|
device);
|
2014-10-21 16:51:07 +00:00
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename Invocation, typename RangeType, typename DeviceAdapter>
|
|
|
|
VTKM_CONT void InvokeSchedule(const Invocation& invocation, RangeType range, DeviceAdapter) const
|
2014-10-21 16:51:07 +00:00
|
|
|
{
|
2016-09-12 14:30:03 +00:00
|
|
|
using Algorithm = vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>;
|
|
|
|
using TaskTypes = typename vtkm::cont::DeviceTaskTypes<DeviceAdapter>;
|
|
|
|
|
|
|
|
// The TaskType class handles the magic of fetching values
|
|
|
|
// for each instance and calling the worklet's function.
|
|
|
|
// The TaskType will evaluate to one of the following classes:
|
|
|
|
//
|
|
|
|
// vtkm::exec::internal::TaskSingular
|
|
|
|
// vtkm::exec::internal::TaskTiling1D
|
|
|
|
// vtkm::exec::internal::TaskTiling3D
|
|
|
|
auto task = TaskTypes::MakeTask(this->Worklet, invocation, range);
|
|
|
|
Algorithm::ScheduleTask(task, range);
|
2014-10-21 16:51:07 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} // namespace vtkm::worklet::internal
|
|
|
|
|
|
|
|
#endif //vtk_m_worklet_internal_DispatcherBase_h
|