ColorTable can provide vtkm::exec::Colortable to a specific device

Previously it wasn't possible to get a color table transfered
to a specific device.
This commit is contained in:
Robert Maynard 2018-07-12 08:28:40 -04:00
parent abfc946f84
commit 6dc06423d8
8 changed files with 130 additions and 34 deletions

@ -0,0 +1,21 @@
# VTK-m VirtualObjectHandle can transfer to a device using runtime `DeviceAdapterId` value
Previously `VirtualObjectHandle` required the caller to know a compile time device adapter tag to
transfer data. This was problematic since in parts of VTK-m you would only have the runtime
`vtkm::cont::DeviceAdapterId` value of the desired device. To than transfer the
`VirtualObjectHandle` you would have to call `FindDeviceAdapterTagAndCall`. All this extra
work was unneeded as `VirtualObjectHandle` internally was immediately converting from
a compile time type to a runtime value.
Here is an example of how you can now transfer a `VirtualObjectHandle` to a device using
a runtime value:
```cpp
template<typename BaseType>
const BaseType* moveToDevice(VirtualObjectHandle<BaseType>& handle,
vtkm::cont::vtkm::cont::DeviceAdapterId deviceId)
{
return handle.PrepareForExecution(deviceId);
}
```

@ -155,6 +155,7 @@ void ColorTable::SetColorSpace(ColorSpace space)
{
if (this->Impl->CSpace != space || this->Impl->HostSideCache.get() == nullptr)
{
this->Impl->HostSideCacheChanged = true;
this->Impl->CSpace = space;
//Remove any existing host and execution data
@ -841,8 +842,8 @@ bool ColorTable::Sample(vtkm::Int32 numSamples,
}
//---------------------------------------------------------------------------
vtkm::cont::VirtualObjectHandle<vtkm::exec::ColorTableBase>* ColorTable::GetHandleForExecution()
const
const vtkm::exec::ColorTableBase* ColorTable::PrepareForExecution(
vtkm::cont::DeviceAdapterId deviceId) const
{
//Only rebuild the array handles that have changed since the last time
//we have modified or color / opacity information
@ -859,17 +860,20 @@ vtkm::cont::VirtualObjectHandle<vtkm::exec::ColorTableBase>* ColorTable::GetHand
this->Impl->OpacityMidSharpHandle = vtkm::cont::make_ArrayHandle(this->Impl->OpacityMidSharp);
}
if (this->Impl->ColorArraysChanged || this->Impl->OpacityArraysChanged)
if (this->Impl->ColorArraysChanged || this->Impl->OpacityArraysChanged ||
this->Impl->HostSideCacheChanged)
{
vtkm::cont::TryExecute(
detail::transfer_color_table_to_device{}, this->Impl->HostSideCache.get(), this->Impl.get());
this->Impl->HostSideCache->Modified();
vtkm::cont::internal::FindDeviceAdapterTagAndCall(deviceId,
VTKM_DEFAULT_DEVICE_ADAPTER_LIST_TAG(),
detail::transfer_color_table_to_device{},
this->Impl->HostSideCache.get(),
this->Impl.get());
}
this->Impl->ColorArraysChanged = false;
this->Impl->OpacityArraysChanged = false;
return this->Impl->ExecHandle.get();
this->Impl->HostSideCacheChanged = false;
return this->Impl->ExecHandle->PrepareForExecution(deviceId);
}
//---------------------------------------------------------------------------

@ -661,10 +661,20 @@ public:
double tolerance = 0.002) const;
/// \brief returns a virtual object handle of the exec color table
/// \brief returns a virtual object pointer of the exec color table
///
/// This object is only valid as long as the ColorTable is unmodified
vtkm::cont::VirtualObjectHandle<vtkm::exec::ColorTableBase>* GetHandleForExecution() const;
/// This pointer is only valid as long as the ColorTable is unmodified
const vtkm::exec::ColorTableBase* PrepareForExecution(vtkm::cont::DeviceAdapterId deviceId) const;
/// \brief returns a virtual object pointer of the exec color table
///
/// This pointer is only valid as long as the ColorTable is unmodified
template <typename DeviceAdapter>
const vtkm::exec::ColorTableBase* PrepareForExecution(DeviceAdapter) const
{
auto deviceId = vtkm::cont::DeviceAdapterTraits<DeviceAdapter>::GetId();
return this->PrepareForExecution(deviceId);
}
/// \brief returns the modified count for the virtual object handle of the exec color table

@ -83,7 +83,7 @@ struct transfer_color_table_to_device
template <typename DeviceAdapter, typename ColorTableInternals>
bool operator()(DeviceAdapter device,
vtkm::exec::ColorTableBase* portal,
ColorTableInternals* internals)
ColorTableInternals* internals) const
{
auto p1 = internals->ColorPosHandle.PrepareForInput(device);
auto p2 = internals->ColorRGBHandle.PrepareForInput(device);
@ -102,6 +102,7 @@ struct transfer_color_table_to_device
portal->ONodes = detail::get_ptr(vtkm::cont::ArrayPortalToIteratorBegin(p3));
portal->Alpha = detail::get_ptr(vtkm::cont::ArrayPortalToIteratorBegin(p4));
portal->MidSharp = detail::get_ptr(vtkm::cont::ArrayPortalToIteratorBegin(p5));
portal->Modified();
return true;
}
};
@ -184,16 +185,14 @@ template <typename T, typename S>
bool ColorTable::Map(const vtkm::cont::ArrayHandle<T, S>& values,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& rgbaOut) const
{
return vtkm::cont::TryExecute(
detail::map_color_table{}, this->GetHandleForExecution(), values, rgbaOut);
return vtkm::cont::TryExecute(detail::map_color_table{}, this, values, rgbaOut);
}
//---------------------------------------------------------------------------
template <typename T, typename S>
bool ColorTable::Map(const vtkm::cont::ArrayHandle<T, S>& values,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>& rgbOut) const
{
return vtkm::cont::TryExecute(
detail::map_color_table{}, this->GetHandleForExecution(), values, rgbOut);
return vtkm::cont::TryExecute(detail::map_color_table{}, this, values, rgbOut);
}
//---------------------------------------------------------------------------
template <typename T, int N, typename S>

@ -47,7 +47,7 @@ struct ColorTableInternals
// BelowRangeColor
// AboveRangeColor
//Note the pointers inside the host side portal are not valid, as they
//are execution
//are execution pointers
std::unique_ptr<vtkm::exec::ColorTableBase> HostSideCache;
//Execution side version of the ColorTableBase.
std::unique_ptr<vtkm::cont::VirtualObjectHandle<vtkm::exec::ColorTableBase>> ExecHandle;
@ -66,6 +66,7 @@ struct ColorTableInternals
vtkm::cont::ArrayHandle<vtkm::Vec<float, 2>> OpacityMidSharpHandle;
bool ColorArraysChanged = true;
bool OpacityArraysChanged = true;
bool HostSideCacheChanged = true;
void RecalculateRange()
{

@ -114,29 +114,26 @@ public:
/// Release all the execution side resources
VTKM_CONT void ReleaseExecutionResources() { this->Internals->ReleaseExecutionResources(); }
/// Get a valid \c VirtualBaseType* with the current control side state for \c DeviceAdapter.
/// Get a valid \c VirtualBaseType* with the current control side state for \c deviceId.
/// VirtualObjectHandle and the returned pointer are analogous to ArrayHandle and Portal
/// The returned pointer will be invalidated if:
/// 1. A new pointer is requested for a different DeviceAdapter
/// 1. A new pointer is requested for a different deviceId
/// 2. VirtualObjectHandle is destroyed
/// 3. Reset or ReleaseResources is called
///
template <typename DeviceAdapter>
VTKM_CONT const VirtualBaseType* PrepareForExecution(DeviceAdapter) const
VTKM_CONT const VirtualBaseType* PrepareForExecution(vtkm::cont::DeviceAdapterId deviceId) const
{
using DeviceInfo = vtkm::cont::DeviceAdapterTraits<DeviceAdapter>;
if (!this->GetValid())
{
throw vtkm::cont::ErrorBadValue("No target object bound");
}
vtkm::cont::DeviceAdapterId deviceId = DeviceInfo::GetId();
if (deviceId < 0 || deviceId >= VTKM_MAX_DEVICE_ADAPTER_ID)
{
std::string msg = "Device '" + DeviceInfo::GetName() + "' has invalid ID of " +
std::to_string(deviceId) + "(VTKM_MAX_DEVICE_ADAPTER_ID = " +
std::to_string(VTKM_MAX_DEVICE_ADAPTER_ID) + ")";
std::string msg = "An invalid device adapter ID of " + std::to_string(deviceId) +
"was used when trying to construct a virtual object. The valid range is between " +
"0 and " + std::to_string(VTKM_MAX_DEVICE_ADAPTER_ID) + ")";
throw vtkm::cont::ErrorBadType(msg);
}
@ -144,7 +141,9 @@ public:
{
if (!this->Internals->Transfers[static_cast<std::size_t>(deviceId)])
{
std::string msg = DeviceInfo::GetName() + " was not in the list specified in Bind";
std::string msg = "The device adapter ID of " + std::to_string(deviceId) +
" was not part of the set of valid adapters when this virtual object was constructed " +
"or last binded to a set of device adapters.";
throw vtkm::cont::ErrorBadType(msg);
}
@ -159,6 +158,20 @@ public:
return this->Internals->Current->PrepareForExecution();
}
/// Get a valid \c VirtualBaseType* with the current control side state for \c DeviceAdapter.
/// VirtualObjectHandle and the returned pointer are analogous to ArrayHandle and Portal
/// The returned pointer will be invalidated if:
/// 1. A new pointer is requested for a different DeviceAdapter
/// 2. VirtualObjectHandle is destroyed
/// 3. Reset or ReleaseResources is called
///
template <typename DeviceAdapter>
VTKM_CONT const VirtualBaseType* PrepareForExecution(DeviceAdapter) const
{
using DeviceInfo = vtkm::cont::DeviceAdapterTraits<DeviceAdapter>;
return this->PrepareForExecution(DeviceInfo::GetId());
}
private:
class TransferInterface
{

@ -381,6 +381,21 @@ public:
VTKM_TEST_ASSERT(result == correct_hsv_values[i],
"incorrect value when interpolating between values");
}
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>> colors_rgb;
table.SetColorSpace(vtkm::cont::ColorSpace::RGB);
table.Map(field, colors_rgb);
const vtkm::Vec<vtkm::UInt8, 3> correct_rgb_values[nvals] = { { 0, 0, 255 }, { 51, 0, 204 },
{ 102, 0, 153 }, { 153, 0, 102 },
{ 204, 0, 51 }, { 255, 0, 0 } };
auto rgb_portal = colors_rgb.GetPortalConstControl();
for (std::size_t i = 0; i < nvals; ++i)
{
auto result = rgb_portal.Get(static_cast<vtkm::Id>(i));
VTKM_TEST_ASSERT(result == correct_rgb_values[i],
"incorrect value when interpolating between values");
}
}
static void TestOpacityOnlyPoints()
@ -430,6 +445,38 @@ public:
}
}
static void TestWorkletTransport()
{
using namespace vtkm::worklet::colorconversion;
vtkm::cont::ColorTable table(vtkm::cont::ColorTable::Preset::LINEAR_GREEN);
VTKM_TEST_ASSERT((table.GetRange() == vtkm::Range{ 0.0, 1.0 }),
"loading linear green table failed with wrong range");
VTKM_TEST_ASSERT((table.GetNumberOfPoints() == 21),
"loading linear green table failed with number of control points");
constexpr vtkm::Id nvals = 3;
constexpr double data[3] = { 0.0f, 0.5f, 1.0f };
auto samples = vtkm::cont::make_ArrayHandle(data, nvals);
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>> colors;
TransferFunction transfer(table.PrepareForExecution(DeviceAdapterTag{}));
vtkm::worklet::DispatcherMapField<TransferFunction, DeviceAdapterTag> dispatcher(transfer);
dispatcher.Invoke(samples, colors);
const vtkm::Vec<vtkm::UInt8, 4> correct_sampling_points[nvals] = { { 14, 28, 31, 255 },
{ 21, 150, 21, 255 },
{ 255, 251, 230, 255 } };
auto portal = colors.GetPortalConstControl();
for (std::size_t i = 0; i < nvals; ++i)
{
auto result = portal.Get(static_cast<vtkm::Id>(i));
VTKM_TEST_ASSERT(result == correct_sampling_points[i],
"incorrect value when interpolating in linear green preset");
}
}
static void TestSampling()
{
@ -498,7 +545,7 @@ public:
{
TestConstructors();
TestLoadPresets();
TestClamping(); //this needs to also verify default opacity
TestClamping();
TestRangeColors();
TestRescaleRange(); //uses Lab
@ -508,6 +555,7 @@ public:
TestOpacityOnlyPoints();
TestWorkletTransport();
TestSampling();
TestLookupTable();
}

@ -68,7 +68,7 @@ class VTKM_ALWAYS_EXPORT ColorTableRGB final : public ColorTableBase
public:
inline VTKM_EXEC vtkm::Vec<float, 3> MapThroughColorSpace(const vtkm::Vec<float, 3>& rgb1,
const vtkm::Vec<float, 3>& rgb2,
float weight) const final;
float weight) const;
};
class VTKM_ALWAYS_EXPORT ColorTableHSV final : public ColorTableBase
@ -76,7 +76,7 @@ class VTKM_ALWAYS_EXPORT ColorTableHSV final : public ColorTableBase
public:
inline VTKM_EXEC vtkm::Vec<float, 3> MapThroughColorSpace(const vtkm::Vec<float, 3>& rgb1,
const vtkm::Vec<float, 3>& rgb2,
float weight) const final;
float weight) const;
};
class VTKM_ALWAYS_EXPORT ColorTableHSVWrap final : public ColorTableBase
@ -84,7 +84,7 @@ class VTKM_ALWAYS_EXPORT ColorTableHSVWrap final : public ColorTableBase
public:
inline VTKM_EXEC vtkm::Vec<float, 3> MapThroughColorSpace(const vtkm::Vec<float, 3>& rgb1,
const vtkm::Vec<float, 3>& rgb2,
float weight) const final;
float weight) const;
};
class VTKM_ALWAYS_EXPORT ColorTableLab final : public ColorTableBase
@ -92,7 +92,7 @@ class VTKM_ALWAYS_EXPORT ColorTableLab final : public ColorTableBase
public:
inline VTKM_EXEC vtkm::Vec<float, 3> MapThroughColorSpace(const vtkm::Vec<float, 3>& rgb1,
const vtkm::Vec<float, 3>& rgb2,
float weight) const final;
float weight) const;
};
class VTKM_ALWAYS_EXPORT ColorTableDiverging final : public ColorTableBase
@ -100,7 +100,7 @@ class VTKM_ALWAYS_EXPORT ColorTableDiverging final : public ColorTableBase
public:
inline VTKM_EXEC vtkm::Vec<float, 3> MapThroughColorSpace(const vtkm::Vec<float, 3>& rgb1,
const vtkm::Vec<float, 3>& rgb2,
float weight) const final;
float weight) const;
};
}
}