Newer
Older
Mark Winter
committed
#pragma once
#include <cstddef>
#include <tuple>
#include "ScriptCommand.h"
#include "mph/tuple_helpers.h"
template <typename Derived, typename ConverterType>
Mark Winter
committed
class ScriptCommandImpl: public ScriptCommand
{
template <typename T>
struct AssertProcessFunc
{
template <typename... Args> static void run(Args&&...) {}
// This condition (!is_same<T,T> is always false) forces waiting for dependent type instantiation
static_assert(!std::is_same<T, T>::value, "HIP_COMPILE: Overload ::execute or ::process<OutT,InT> method in script command subclass, or define script command using SCR_CMD instead of SCR_CMD_NOPROC.");
Mark Winter
committed
};
using ProcessFunc = AssertProcessFunc<Derived>;
public:
// Argument load/conversion access types
using ArgConverter = ConverterType;
using ArgError = typename ArgConverter::ArgError;
Mark Winter
committed
// Script/converted argument types from arg parser
using ScriptTypes = typename ArgConverter::ScriptTypes;
using ArgTypes = typename ArgConverter::ArgTypes;
Mark Winter
committed
// Pointers to arguments
using ScriptPtrs = typename ArgConverter::ScriptPtrs;
using ArgPtrs = typename ArgConverter::ArgPtrs;
Mark Winter
committed
// Selectors
using OptionalSel = typename ArgConverter::OptionalSel;
using DeferredSel = typename ArgConverter::DeferredSel;
using DeferredOutSel = typename ArgConverter::DeferredOutSel;
using DeferredOutImSel = typename ArgConverter::DeferredOutImSel;
using DeferredInOptSel = typename ArgConverter::DeferredInOptSel;
using NondeferredSel = typename ArgConverter::NondeferredSel;
using NondeferOutSel = typename ArgConverter::NondeferOutSel;
using NondeferInOptSel = typename ArgConverter::NondeferInOptSel;
Mark Winter
committed
// Deferred concrete-types
template <typename OutT, typename InT>
using ConcreteArgTypes = typename ArgConverter::template ConcreteArgTypes<OutT, InT>;
Mark Winter
committed
template <typename InT>
using OutMap = typename ArgConverter::template OutMap<InT>;
Mark Winter
committed
public:
/////////
// These are the four interface functions that are registered in the m_commands FuncPtrs list
Mark Winter
committed
// (dispatch, usage, help, info)
Mark Winter
committed
// Script engine-dependent function to dispatch parameters
inline static SCR_DISPATCH_FUNC_DEF(dispatch)
inline static SCR_HELP_FUNC_DECL(help)
{
if ( Derived::helpStr.size() > 0 )
return Derived::usage() + "\n\n" + std::string(Derived::helpStr);
Mark Winter
committed
else
return Derived::usage();
}
inline static SCR_USAGE_FUNC_DECL(usage)
{
// TODO: Fix the output wrapping here
return usageOutput(ArgConverter::outargstr())
+ moduleName() + "." + Derived::commandName()
+ "("+ ArgConverter::inoptargstr() + ")";
Mark Winter
committed
}
inline static SCR_INFO_FUNC_DECL(info)
{
command = Derived::commandName();
help = Derived::help();
outArgs = ArgConverter::outargstr();
inArgs = ArgConverter::inoptargstr();
Mark Winter
committed
}
private:
inline static std::string usageOutput(const std::string& outStr)
{
if ( outStr.empty() )
return outStr;
else
return std::string("[") + outStr + "] = ";
}
public:
Mark Winter
committed
// Non-overloadable - Handles argument conversion and dispatches to execute command
// NOTE: default execute command checks for deferred types and passes to
// the templated process function.
template <typename... ScriptInterface>
static void convert_dispatch(ScriptInterface&&... scriptioArgs)
{
try
{
// Subset of arguments that have concrete type (non-deferred)
using ConcreteArgs = typename NondeferredSel::template type<ArgTypes>;
Mark Winter
committed
// TODO: Specialize output types for python to make sure memory is cleaned up
Mark Winter
committed
// Points to the C++ arguments converted from script types
// NOTE: These are partially converted as the deferred arguments are converted in ::process<>
ArgPtrs convertedPtrs;
// Memory for script objects corresponding to arguments
// NOTE: These local objects are necessary for temporary ownership of non-deferred Python outputs
ScriptTypes scriptObjects;
ScriptPtrs scriptPtrs = mph::tuple_addr_of(scriptObjects);
// Load script pointers from script engine inputs
ArgConverter::load(scriptPtrs, std::forward<ScriptInterface>(scriptioArgs)...);
Mark Winter
committed
// NOTE: Requires that args are default-constructible types
ConcreteArgs convertedArgs;
// Hook up convertedPtrs (non-deferred point to concreteArgs, deferred same as scriptPtrs)
DeferredSel::select(convertedPtrs) = DeferredSel::select(scriptPtrs);
NondeferredSel::select(convertedPtrs) = mph::tuple_addr_of(convertedArgs);
// Load default values for optional arguments (can't be deferred)
ArgConverter::setOptionalDefaults(convertedPtrs);
Mark Winter
committed
// Convert non-deferred inputs to appropriate arg types
ArgConverter::convertSelected(convertedPtrs, scriptPtrs, NondeferInOptSel{});
Mark Winter
committed
// TODO: Figure out how to solve the dims inference problem
// TODO: Currently no support for creating non-deferred output images
// Create non-deferred outputs
//ArgConverter::createOutIm(convertedPtrs, scriptPtrs, dims, NondeferOutImSel{});
Mark Winter
committed
// Run backend cuda filter using default execute() -> process<OutT,InT>()
// or run overloaded ::execute or ::process<OutT,InT> functions
exec_dispatch(mph::tuple_deref(convertedPtrs));
// Convert outputs to script types
ArgConverter::convertSelected(scriptPtrs, convertedPtrs, NondeferOutSel{});
Mark Winter
committed
// Load all outputs into script output structure (Necessary for Python)
ArgConverter::store(scriptPtrs, std::forward<ScriptInterface>(scriptioArgs)...);
Mark Winter
committed
}
catch ( ArgError& ae )
{
Mark Winter
committed
Script::errorMsg(ae.what());
Mark Winter
committed
}
catch ( std::exception& e )
{
std::string msg("Internal error: ");
msg += e.what();
Mark Winter
committed
Script::errorMsg(msg.c_str());
Mark Winter
committed
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
}
}
private:
template <typename... Args>
static void exec_dispatch(std::tuple<Args...> ioArgs)
{
Derived::exec_dispatch_impl(ioArgs, mph::make_index_sequence<sizeof... (Args)>());
}
template <typename... Args, size_t... Is>
static void exec_dispatch_impl(std::tuple<Args...> ioArgs, mph::index_sequence<Is...>)
{
Derived::execute(std::forward<Args>(std::get<Is>(ioArgs))...);
}
private:
/////////////////////////
// execute - (Static-overloadable)
// Default execute function dispatches to image-type templated
// process<OutT,InT>(Args...) function
/////////////////////////
template <typename... Args>
static void execute(Args&&... args)
{
static_assert(ArgConverter::has_deferred_image_inputs(), "HIP_COMPILE: Argument layout has no dynamic image inputs. Please overload default ::execute() function!");
Mark Winter
committed
Script::IdType type = ArgConverter::getInputType(std::forward<Args>(args)...);
Mark Winter
committed
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
if ( type == Script::TypeToIdMap<bool>::typeId )
{
Derived::template process<OutMap<bool>, bool>(std::forward<Args>(args)...);
}
else if ( type == Script::TypeToIdMap<uint8_t>::typeId )
{
Derived::template process<OutMap<uint8_t>, uint8_t>(std::forward<Args>(args)...);
}
else if ( type == Script::TypeToIdMap<uint16_t>::typeId )
{
Derived::template process<OutMap<uint16_t>, uint16_t>(std::forward<Args>(args)...);
}
else if ( type == Script::TypeToIdMap<int16_t>::typeId )
{
Derived::template process<OutMap<int16_t>, int16_t>(std::forward<Args>(args)...);
}
else if ( type == Script::TypeToIdMap<uint32_t>::typeId )
{
Derived::template process<OutMap<uint32_t>, uint32_t>(std::forward<Args>(args)...);
}
else if ( type == Script::TypeToIdMap<int32_t>::typeId )
{
Derived::template process<OutMap<int32_t>, int32_t>(std::forward<Args>(args)...);
}
else if ( type == Script::TypeToIdMap<float>::typeId )
{
Derived::template process<OutMap<float>, float>(std::forward<Args>(args)...);
}
else if ( type == Script::TypeToIdMap<double>::typeId )
{
Derived::template process<OutMap<double>, double>(std::forward<Args>(args)...);
}
else
{
throw ArgError("Image type unsupported (%x)", type);
Mark Winter
committed
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
}
}
/////////////////////////
// process - (Static-overloadable)
// Default process<OutT,InT> function creates deferred io and dispatches
// to the class-specified cuda processing function
/////////////////////////
template <typename OutType, typename InType, typename... Args>
static void process(Args&&... args)
{
// Deferred types (Can now be fully defined)
using DeferredArgs = ConcreteArgTypes<OutType, InType>;
using DeferredPtrs = typename mph::tuple_ptr_t<DeferredArgs>;
using DeferredInArgs = typename DeferredInOptSel::template type<DeferredArgs>;
using DeferredOutArgs = typename DeferredOutSel::template type<DeferredArgs>;
auto argRefs = std::tie(args...);
ArgPtrs argPtrs = mph::tuple_addr_of(argRefs);
// Pointers to fully-converted arguments to be passed (by reference) to the cuda processing function
DeferredPtrs convertedPtrs;
// Storage for deferred in/out types
DeferredInArgs concreteInArgs;
DeferredOutArgs concreteOutArgs;
// Hook up convertedPtrs all non-deferred are already converted, deferred get hooked locals
NondeferredSel::select(convertedPtrs) = NondeferredSel::select(argPtrs);
DeferredInOptSel::select(convertedPtrs) = mph::tuple_addr_of(concreteInArgs);
DeferredOutSel::select(convertedPtrs) = mph::tuple_addr_of(concreteOutArgs);
// Convert deferred inputs to appropriate arg types
ArgConverter::convertSelected(convertedPtrs, argPtrs, DeferredInOptSel{});
Mark Winter
committed
// Create imageref outputs
// TODO: Better image dims inference
Script::DimInfo dimInfo = ArgConverter::getInputDimInfo(argRefs);
ArgConverter::createOutImRefs(convertedPtrs, argPtrs, dimInfo);
Mark Winter
committed
// Run backend cuda filter
run_dispatch(mph::tuple_deref(convertedPtrs));
// Convert deferred outputs to script types
ArgConverter::convertSelected(argPtrs, convertedPtrs, DeferredOutSel{});
Mark Winter
committed
}
template <typename... Args>
static void run_dispatch(std::tuple<Args...> runArgs)
{
Derived::run_dispatch_impl(runArgs, mph::make_index_sequence<sizeof... (Args)>());
}
template <typename... Args, size_t... Is>
static void run_dispatch_impl(std::tuple<Args...> runArgs, mph::index_sequence<Is...>)
{
Derived::ProcessFunc::run(std::forward<Args>(std::get<Is>(runArgs))...);
}
};