Redesign vtkm::cont::ColorTable to work with separable compilation.

This commit is contained in:
Robert Maynard 2018-10-26 11:53:52 -04:00
parent e549cea8eb
commit 169ca722b3
9 changed files with 352 additions and 251 deletions

@ -35,6 +35,8 @@
#include <vtkm/exec/FunctorBase.h>
#include <vtkm/cont/ColorTable.hxx>
#include <sstream>
#include <string>
#include <vector>

@ -125,6 +125,7 @@ set(sources
BoundsGlobalCompute.cxx
CellSet.cxx
CellSetStructured.cxx
ColorTable.cxx
DataSet.cxx
DataSetBuilderExplicit.cxx
DataSetBuilderRectilinear.cxx
@ -154,7 +155,6 @@ set(sources
set(device_sources
ArrayRangeCompute.cxx
CellSetExplicit.cxx
ColorTable.cxx
CoordinateSystem.cxx
)

@ -23,6 +23,9 @@
#include <vtkm/cont/ColorTable.h>
#include <vtkm/cont/ColorTable.hxx>
#include <vtkm/cont/ColorTablePrivate.hxx>
#include <vtkm/cont/ErrorBadType.h>
#include <vtkm/cont/TryExecute.h>
namespace vtkm
{
@ -44,7 +47,7 @@ ColorTable::ColorTable(vtkm::cont::ColorTable::Preset preset)
if (!loaded)
{ //if we failed to load the requested color table, call SetColorSpace
//so that the internal host side cache is constructed and we leave
//the constructor in a valid state. We use RGB as it is the default
//the constructor in a valid state. We use LAB as it is the default
//when the no parameter constructor is called
this->SetColorSpace(ColorSpace::LAB);
}
@ -59,7 +62,7 @@ ColorTable::ColorTable(const std::string& name)
if (!loaded)
{ //if we failed to load the requested color table, call SetColorSpace
//so that the internal host side cache is constructed and we leave
//the constructor in a valid state. We use RGB as it is the default
//the constructor in a valid state. We use LAB as it is the default
//when the no parameter constructor is called
this->SetColorSpace(ColorSpace::LAB);
}
@ -153,47 +156,42 @@ ColorSpace ColorTable::GetColorSpace() const
//----------------------------------------------------------------------------
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
//Remove any existing host information
using HandleType = vtkm::cont::VirtualObjectHandle<vtkm::exec::ColorTableBase>;
switch (space)
{
case vtkm::cont::ColorSpace::RGB:
{
auto* hostPortal = new vtkm::exec::ColorTableRGB();
this->Impl->ExecHandle.reset(new HandleType(hostPortal, false));
this->Impl->HostSideCache.reset(hostPortal);
break;
}
case vtkm::cont::ColorSpace::HSV:
{
auto* hostPortal = new vtkm::exec::ColorTableHSV();
this->Impl->ExecHandle.reset(new HandleType(hostPortal, false));
this->Impl->HostSideCache.reset(hostPortal);
break;
}
case vtkm::cont::ColorSpace::HSV_WRAP:
{
auto* hostPortal = new vtkm::exec::ColorTableHSVWrap();
this->Impl->ExecHandle.reset(new HandleType(hostPortal, false));
this->Impl->HostSideCache.reset(hostPortal);
break;
}
case vtkm::cont::ColorSpace::LAB:
{
auto* hostPortal = new vtkm::exec::ColorTableLab();
this->Impl->ExecHandle.reset(new HandleType(hostPortal, false));
this->Impl->HostSideCache.reset(hostPortal);
break;
}
case vtkm::cont::ColorSpace::DIVERGING:
{
auto* hostPortal = new vtkm::exec::ColorTableDiverging();
this->Impl->ExecHandle.reset(new HandleType(hostPortal, false));
this->Impl->HostSideCache.reset(hostPortal);
break;
}
@ -788,65 +786,32 @@ bool ColorTable::FillOpacityTableFromDataPointer(vtkm::Int32 n, const float* ptr
this->Impl->OpacityArraysChanged = true;
return true;
}
//---------------------------------------------------------------------------
bool ColorTable::Sample(vtkm::Int32 numSamples,
vtkm::cont::ColorTableSamplesRGBA& samples,
double tolerance) const
vtkm::Id ColorTable::GetModifiedCount() const
{
if (numSamples <= 1)
{
return false;
}
samples.NumberOfSamples = numSamples;
samples.SampleRange = this->GetRange();
return sampleColorTable(this, numSamples, samples.Samples, tolerance, true);
return this->Impl->HostSideCache->GetModifiedCount();
}
//---------------------------------------------------------------------------
bool ColorTable::Sample(vtkm::Int32 numSamples,
vtkm::cont::ColorTableSamplesRGB& samples,
double tolerance) const
//----------------------------------------------------------------------------
bool ColorTable::NeedToCreateExecutionColorTable() const
{
if (numSamples <= 1)
{
return false;
}
samples.NumberOfSamples = numSamples;
samples.SampleRange = this->GetRange();
return sampleColorTable(this, numSamples, samples.Samples, tolerance, true);
return this->Impl->HostSideCacheChanged;
}
//---------------------------------------------------------------------------
bool ColorTable::Sample(vtkm::Int32 numSamples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& colors,
double tolerance) const
//----------------------------------------------------------------------------
void ColorTable::UpdateExecutionColorTable(
vtkm::cont::VirtualObjectHandle<vtkm::exec::ColorTableBase>* handle) const
{
if (numSamples <= 1)
{
return false;
}
return sampleColorTable(this, numSamples, colors, tolerance, false);
this->Impl->ExecHandle.reset(handle);
}
//---------------------------------------------------------------------------
bool ColorTable::Sample(vtkm::Int32 numSamples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>& colors,
double tolerance) const
{
if (numSamples <= 1)
{
return false;
}
return sampleColorTable(this, numSamples, colors, tolerance, false);
}
//---------------------------------------------------------------------------
const vtkm::exec::ColorTableBase* ColorTable::PrepareForExecution(
vtkm::cont::DeviceAdapterId deviceId) const
//----------------------------------------------------------------------------
ColorTable::TransferState ColorTable::GetExecutionDataForTransfer() const
{
//Only rebuild the array handles that have changed since the last time
//we have modified or color / opacity information
if (this->Impl->ColorArraysChanged)
{
this->Impl->ColorPosHandle = vtkm::cont::make_ArrayHandle(this->Impl->ColorNodePos);
@ -860,56 +825,32 @@ const vtkm::exec::ColorTableBase* ColorTable::PrepareForExecution(
this->Impl->OpacityMidSharpHandle = vtkm::cont::make_ArrayHandle(this->Impl->OpacityMidSharp);
}
bool transfered = true;
if (this->Impl->ColorArraysChanged || this->Impl->OpacityArraysChanged ||
this->Impl->HostSideCacheChanged)
{
transfered = vtkm::cont::TryExecuteOnDevice(deviceId,
detail::transfer_color_table_to_device{},
this->Impl->HostSideCache.get(),
this->Impl.get());
}
if (!transfered)
{
throwFailedRuntimeDeviceTransfer("ColorTable", deviceId);
}
TransferState state = { (this->Impl->ColorArraysChanged || this->Impl->OpacityArraysChanged ||
this->Impl->HostSideCacheChanged),
this->Impl->HostSideCache.get(),
this->Impl->ColorPosHandle,
this->Impl->ColorRGBHandle,
this->Impl->OpacityPosHandle,
this->Impl->OpacityAlphaHandle,
this->Impl->OpacityMidSharpHandle };
this->Impl->ColorArraysChanged = false;
this->Impl->OpacityArraysChanged = false;
this->Impl->HostSideCacheChanged = false;
return this->Impl->ExecHandle->PrepareForExecution(deviceId);
return state;
}
//---------------------------------------------------------------------------
vtkm::Id ColorTable::GetModifiedCount() const
//----------------------------------------------------------------------------
vtkm::exec::ColorTableBase* ColorTable::GetControlRepresentation() const
{
return this->Impl->HostSideCache->GetModifiedCount();
return this->Impl->HostSideCache.get();
}
/*
#define ColorTableExportMapFunctions(T) \
template VTKM_CONT_EXPORT bool ColorTable::Map( \
const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic>&, \
const vtkm::cont::ColorTableSamplesRGBA&, \
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>&) const; \
template VTKM_CONT_EXPORT bool ColorTable::Map( \
const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic>&, \
const vtkm::cont::ColorTableSamplesRGB&, \
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>&) const; \
template VTKM_CONT_EXPORT bool ColorTable::Map( \
const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic>&, \
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>&) const; \
template VTKM_CONT_EXPORT bool ColorTable::Map( \
const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic>&, \
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>&) const;
ColorTableExportMapFunctions(char);
ColorTableExportMapFunctions(vtkm::UInt8);
ColorTableExportMapFunctions(vtkm::Int8);
ColorTableExportMapFunctions(vtkm::Float32);
ColorTableExportMapFunctions(vtkm::Float64);
#undef ColorTableExportMapFunctions
*/
//----------------------------------------------------------------------------
vtkm::cont::VirtualObjectHandle<vtkm::exec::ColorTableBase> const* ColorTable::GetExecutionHandle()
const
{
return this->Impl->ExecHandle.get();
}
}
} //namespace vtkm::cont

@ -497,9 +497,9 @@ public:
///
/// \endcode
template <typename T, typename S>
bool Map(const vtkm::cont::ArrayHandle<T, S>& values,
const vtkm::cont::ColorTableSamplesRGBA& samples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& rgbaOut) const;
inline bool Map(const vtkm::cont::ArrayHandle<T, S>& values,
const vtkm::cont::ColorTableSamplesRGBA& samples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& rgbaOut) const;
/// \brief Sample each value through an intermediate lookup/sample table to generate RGB colors
///
@ -518,39 +518,39 @@ public:
///
/// \endcode
template <typename T, typename S>
bool Map(const vtkm::cont::ArrayHandle<T, S>& values,
const vtkm::cont::ColorTableSamplesRGB& samples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>& rgbaOut) const;
inline bool Map(const vtkm::cont::ArrayHandle<T, S>& values,
const vtkm::cont::ColorTableSamplesRGB& samples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>& rgbaOut) const;
/// \brief Use magnitude of a vector with a sample table to generate RGBA colors
///
template <typename T, int N, typename S>
bool MapMagnitude(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
const vtkm::cont::ColorTableSamplesRGBA& samples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& rgbaOut) const;
inline bool MapMagnitude(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
const vtkm::cont::ColorTableSamplesRGBA& samples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& rgbaOut) const;
/// \brief Use magnitude of a vector with a sample table to generate RGB colors
///
template <typename T, int N, typename S>
bool MapMagnitude(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
const vtkm::cont::ColorTableSamplesRGB& samples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>& rgbaOut) const;
inline bool MapMagnitude(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
const vtkm::cont::ColorTableSamplesRGB& samples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>& rgbaOut) const;
/// \brief Use a single component of a vector with a sample table to generate RGBA colors
///
template <typename T, int N, typename S>
bool MapComponent(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
vtkm::IdComponent comp,
const vtkm::cont::ColorTableSamplesRGBA& samples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& rgbaOut) const;
inline bool MapComponent(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
vtkm::IdComponent comp,
const vtkm::cont::ColorTableSamplesRGBA& samples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& rgbaOut) const;
/// \brief Use a single component of a vector with a sample table to generate RGB colors
///
template <typename T, int N, typename S>
bool MapComponent(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
vtkm::IdComponent comp,
const vtkm::cont::ColorTableSamplesRGB& samples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>& rgbOut) const;
inline bool MapComponent(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
vtkm::IdComponent comp,
const vtkm::cont::ColorTableSamplesRGB& samples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>& rgbOut) const;
/// \brief Interpolate each value through the color table to generate RGBA colors
@ -560,8 +560,8 @@ public:
///
/// Note: This is more costly than using Sample/Map with the generated intermediate lookup table
template <typename T, typename S>
bool Map(const vtkm::cont::ArrayHandle<T, S>& values,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& rgbaOut) const;
inline bool Map(const vtkm::cont::ArrayHandle<T, S>& values,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& rgbaOut) const;
/// \brief Interpolate each value through the color table to generate RGB colors
///
@ -570,34 +570,34 @@ public:
///
/// Note: This is more costly than using Sample/Map with the generated intermediate lookup table
template <typename T, typename S>
bool Map(const vtkm::cont::ArrayHandle<T, S>& values,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>& rgbOut) const;
inline bool Map(const vtkm::cont::ArrayHandle<T, S>& values,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>& rgbOut) const;
/// \brief Use magnitude of a vector to generate RGBA colors
///
template <typename T, int N, typename S>
bool MapMagnitude(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& rgbaOut) const;
inline bool MapMagnitude(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& rgbaOut) const;
/// \brief Use magnitude of a vector to generate RGB colors
///
template <typename T, int N, typename S>
bool MapMagnitude(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>& rgbOut) const;
inline bool MapMagnitude(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>& rgbOut) const;
/// \brief Use a single component of a vector to generate RGBA colors
///
template <typename T, int N, typename S>
bool MapComponent(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
vtkm::IdComponent comp,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& rgbaOut) const;
inline bool MapComponent(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
vtkm::IdComponent comp,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& rgbaOut) const;
/// \brief Use a single component of a vector to generate RGB colors
///
template <typename T, int N, typename S>
bool MapComponent(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
vtkm::IdComponent comp,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>& rgbOut) const;
inline bool MapComponent(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
vtkm::IdComponent comp,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>& rgbOut) const;
/// \brief generate RGB colors using regular spaced samples along the range.
@ -611,9 +611,9 @@ public:
/// - ((max-min) / numSamples) * numSamples
///
/// Note: This will return false if the number of samples is less than 2
bool Sample(vtkm::Int32 numSamples,
vtkm::cont::ColorTableSamplesRGBA& samples,
double tolerance = 0.002) const;
inline bool Sample(vtkm::Int32 numSamples,
vtkm::cont::ColorTableSamplesRGBA& samples,
double tolerance = 0.002) const;
/// \brief generate a sample lookup table using regular spaced samples along the range.
///
@ -626,9 +626,9 @@ public:
/// - ((max-min) / numSamples) * numSamples
///
/// Note: This will return false if the number of samples is less than 2
bool Sample(vtkm::Int32 numSamples,
vtkm::cont::ColorTableSamplesRGB& samples,
double tolerance = 0.002) const;
inline bool Sample(vtkm::Int32 numSamples,
vtkm::cont::ColorTableSamplesRGB& samples,
double tolerance = 0.002) const;
/// \brief generate RGBA colors using regular spaced samples along the range.
///
@ -641,9 +641,9 @@ public:
/// - ((max-min) / numSamples) * numSamples
///
/// Note: This will return false if the number of samples is less than 2
bool Sample(vtkm::Int32 numSamples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& colors,
double tolerance = 0.002) const;
inline bool Sample(vtkm::Int32 numSamples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& colors,
double tolerance = 0.002) const;
/// \brief generate RGB colors using regular spaced samples along the range.
///
@ -656,21 +656,46 @@ public:
/// - ((max-min) / numSamples) * numSamples
///
/// Note: This will return false if the number of samples is less than 2
bool Sample(vtkm::Int32 numSamples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>& colors,
double tolerance = 0.002) const;
inline bool Sample(vtkm::Int32 numSamples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>& colors,
double tolerance = 0.002) const;
/// \brief returns a virtual object pointer of the exec color table
///
/// This pointer is only valid as long as the ColorTable is unmodified
const vtkm::exec::ColorTableBase* PrepareForExecution(vtkm::cont::DeviceAdapterId deviceId) const;
inline const vtkm::exec::ColorTableBase* PrepareForExecution(
vtkm::cont::DeviceAdapterId deviceId) const;
/// \brief returns the modified count for the virtual object handle of the exec color table
///
/// The modified count allows consumers of a shared color table to keep track
/// if the color table has been modified since the last time they used it.
vtkm::Id GetModifiedCount() const;
struct TransferState
{
bool NeedsTransfer;
vtkm::exec::ColorTableBase* Portal;
const vtkm::cont::ArrayHandle<double>& ColorPosHandle;
const vtkm::cont::ArrayHandle<vtkm::Vec<float, 3>>& ColorRGBHandle;
const vtkm::cont::ArrayHandle<double>& OpacityPosHandle;
const vtkm::cont::ArrayHandle<float>& OpacityAlphaHandle;
const vtkm::cont::ArrayHandle<vtkm::Vec<float, 2>>& OpacityMidSharpHandle;
};
private:
bool NeedToCreateExecutionColorTable() const;
//takes ownership of the pointer passed in
void UpdateExecutionColorTable(
vtkm::cont::VirtualObjectHandle<vtkm::exec::ColorTableBase>*) const;
ColorTable::TransferState GetExecutionDataForTransfer() const;
vtkm::exec::ColorTableBase* GetControlRepresentation() const;
vtkm::cont::VirtualObjectHandle<vtkm::exec::ColorTableBase> const* GetExecutionHandle() const;
};
}
} //namespace vtkm::cont

@ -17,6 +17,10 @@
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_cont_ColorTable_hxx
#define vtk_m_cont_ColorTable_hxx
#include <vtkm/cont/ArrayHandleCounting.h>
#include <vtkm/cont/ArrayHandleTransform.h>
#include <vtkm/cont/TryExecute.h>
@ -50,44 +54,43 @@ inline T* get_ptr(stdext::checked_array_iterator<T*> t)
}
#endif
struct map_color_table
{
template <typename DeviceAdapter, typename ColorTable, typename... Args>
bool operator()(DeviceAdapter device, ColorTable&& colors, Args&&... args) const
{
vtkm::worklet::colorconversion::TransferFunction transfer(colors->PrepareForExecution(device));
vtkm::worklet::Invoker invoke(device);
invoke(transfer, std::forward<Args>(args)...);
return true;
}
};
struct transfer_color_table_to_device
{
template <typename DeviceAdapter, typename ColorTableInternals>
bool operator()(DeviceAdapter device,
vtkm::exec::ColorTableBase* portal,
ColorTableInternals* internals) const
template <typename DeviceAdapter>
inline bool operator()(DeviceAdapter device, vtkm::cont::ColorTable::TransferState&& state) const
{
auto p1 = internals->ColorPosHandle.PrepareForInput(device);
auto p2 = internals->ColorRGBHandle.PrepareForInput(device);
auto p3 = internals->OpacityPosHandle.PrepareForInput(device);
auto p4 = internals->OpacityAlphaHandle.PrepareForInput(device);
auto p5 = internals->OpacityMidSharpHandle.PrepareForInput(device);
auto p1 = state.ColorPosHandle.PrepareForInput(device);
auto p2 = state.ColorRGBHandle.PrepareForInput(device);
auto p3 = state.OpacityPosHandle.PrepareForInput(device);
auto p4 = state.OpacityAlphaHandle.PrepareForInput(device);
auto p5 = state.OpacityMidSharpHandle.PrepareForInput(device);
//The rest of the data member on portal are set when-ever the user
//modifies the ColorTable instance and don't need to specified here
portal->ColorSize = static_cast<vtkm::Int32>(internals->ColorPosHandle.GetNumberOfValues());
portal->OpacitySize = static_cast<vtkm::Int32>(internals->OpacityPosHandle.GetNumberOfValues());
state.Portal->ColorSize = static_cast<vtkm::Int32>(state.ColorPosHandle.GetNumberOfValues());
state.Portal->OpacitySize =
static_cast<vtkm::Int32>(state.OpacityPosHandle.GetNumberOfValues());
portal->ColorNodes = detail::get_ptr(vtkm::cont::ArrayPortalToIteratorBegin(p1));
portal->RGB = detail::get_ptr(vtkm::cont::ArrayPortalToIteratorBegin(p2));
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();
state.Portal->ColorNodes = detail::get_ptr(vtkm::cont::ArrayPortalToIteratorBegin(p1));
state.Portal->RGB = detail::get_ptr(vtkm::cont::ArrayPortalToIteratorBegin(p2));
state.Portal->ONodes = detail::get_ptr(vtkm::cont::ArrayPortalToIteratorBegin(p3));
state.Portal->Alpha = detail::get_ptr(vtkm::cont::ArrayPortalToIteratorBegin(p4));
state.Portal->MidSharp = detail::get_ptr(vtkm::cont::ArrayPortalToIteratorBegin(p5));
state.Portal->Modified();
return true;
}
};
struct map_color_table
{
template <typename DeviceAdapter, typename ColorTable, typename... Args>
inline bool operator()(DeviceAdapter device, ColorTable&& colors, Args&&... args) const
{
vtkm::worklet::colorconversion::TransferFunction transfer(colors->PrepareForExecution(device));
vtkm::worklet::Invoker invoke(device);
invoke(transfer, std::forward<Args>(args)...);
return true;
}
};
@ -215,5 +218,206 @@ bool ColorTable::MapComponent(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>&
using namespace vtkm::worklet::colorconversion;
return this->Map(vtkm::cont::make_ArrayHandleTransform(values, ComponentPortal(comp)), rgbOut);
}
namespace
{
template <typename T>
inline vtkm::cont::ArrayHandle<T> buildSampleHandle(vtkm::Int32 numSamples,
T start,
T end,
T inc,
bool appendNanAndRangeColors)
{
//number of samples + end + appendNanAndRangeColors
vtkm::Int32 allocationSize = (appendNanAndRangeColors) ? numSamples + 5 : numSamples + 1;
vtkm::cont::ArrayHandle<T> handle;
handle.Allocate(allocationSize);
auto portal = handle.GetPortalControl();
vtkm::Id index = 0;
//Insert the below range first
if (appendNanAndRangeColors)
{
portal.Set(index++, std::numeric_limits<T>::lowest()); //below
}
//add number of samples which doesn't account for the end
T value = start;
for (vtkm::Int32 i = 0; i < numSamples; ++i, ++index, value += inc)
{
portal.Set(index, value);
}
portal.Set(index++, end);
if (appendNanAndRangeColors)
{
//push back the last value again so that when lookups near the max value
//occur we don't need to clamp as if they are out-of-bounds they will
//land in the extra 'end' color
portal.Set(index++, end);
portal.Set(index++, std::numeric_limits<T>::max()); //above
portal.Set(index++, vtkm::Nan<T>()); //nan
}
return handle;
}
template <typename ColorTable, typename OutputColors>
inline bool sampleColorTable(const ColorTable* self,
vtkm::Int32 numSamples,
OutputColors& colors,
double tolerance,
bool appendNanAndRangeColors)
{
vtkm::Range r = self->GetRange();
//We want the samples to start at Min, and end at Max so that means
//we want actually to interpolate numSample - 1 values. For example
//for range 0 - 1, we want the values 0, 0.5, and 1.
const double d_samples = static_cast<double>(numSamples - 1);
const double d_delta = r.Length() / d_samples;
if (r.Min > static_cast<double>(std::numeric_limits<float>::lowest()) &&
r.Max < static_cast<double>(std::numeric_limits<float>::max()))
{
//we can try and see if float space has enough resolution
const float f_samples = static_cast<float>(numSamples - 1);
const float f_start = static_cast<float>(r.Min);
const float f_delta = static_cast<float>(r.Length()) / f_samples;
const float f_end = f_start + (f_delta * f_samples);
if (vtkm::Abs(static_cast<double>(f_end) - r.Max) <= tolerance &&
vtkm::Abs(static_cast<double>(f_delta) - d_delta) <= tolerance)
{
auto handle =
buildSampleHandle((numSamples - 1), f_start, f_end, f_delta, appendNanAndRangeColors);
return self->Map(handle, colors);
}
}
//otherwise we need to use double space
auto handle = buildSampleHandle((numSamples - 1), r.Min, r.Max, d_delta, appendNanAndRangeColors);
return self->Map(handle, colors);
}
}
//---------------------------------------------------------------------------
bool ColorTable::Sample(vtkm::Int32 numSamples,
vtkm::cont::ColorTableSamplesRGBA& samples,
double tolerance) const
{
if (numSamples <= 1)
{
return false;
}
samples.NumberOfSamples = numSamples;
samples.SampleRange = this->GetRange();
return sampleColorTable(this, numSamples, samples.Samples, tolerance, true);
}
//---------------------------------------------------------------------------
bool ColorTable::Sample(vtkm::Int32 numSamples,
vtkm::cont::ColorTableSamplesRGB& samples,
double tolerance) const
{
if (numSamples <= 1)
{
return false;
}
samples.NumberOfSamples = numSamples;
samples.SampleRange = this->GetRange();
return sampleColorTable(this, numSamples, samples.Samples, tolerance, true);
}
//---------------------------------------------------------------------------
bool ColorTable::Sample(vtkm::Int32 numSamples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& colors,
double tolerance) const
{
if (numSamples <= 1)
{
return false;
}
return sampleColorTable(this, numSamples, colors, tolerance, false);
}
//---------------------------------------------------------------------------
bool ColorTable::Sample(vtkm::Int32 numSamples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>& colors,
double tolerance) const
{
if (numSamples <= 1)
{
return false;
}
return sampleColorTable(this, numSamples, colors, tolerance, false);
}
//---------------------------------------------------------------------------
const vtkm::exec::ColorTableBase* ColorTable::PrepareForExecution(
vtkm::cont::DeviceAdapterId device) const
{
//Build the ColorTable instance that is needed for execution
if (this->NeedToCreateExecutionColorTable())
{
auto space = this->GetColorSpace();
auto hostPortal = this->GetControlRepresentation();
//Remove any existing host and execution data. The allocation of the
//virtual object handle needs to occur in the .hxx so that it happens
//in the same library as the user and will be a valid virtual object
using HandleType = vtkm::cont::VirtualObjectHandle<vtkm::exec::ColorTableBase>;
switch (space)
{
case vtkm::cont::ColorSpace::RGB:
{
this->UpdateExecutionColorTable(
new HandleType(static_cast<vtkm::exec::ColorTableRGB*>(hostPortal), false));
break;
}
case vtkm::cont::ColorSpace::HSV:
{
this->UpdateExecutionColorTable(
new HandleType(static_cast<vtkm::exec::ColorTableHSV*>(hostPortal), false));
break;
}
case vtkm::cont::ColorSpace::HSV_WRAP:
{
this->UpdateExecutionColorTable(
new HandleType(static_cast<vtkm::exec::ColorTableHSVWrap*>(hostPortal), false));
break;
}
case vtkm::cont::ColorSpace::LAB:
{
this->UpdateExecutionColorTable(
new HandleType(static_cast<vtkm::exec::ColorTableLab*>(hostPortal), false));
break;
}
case vtkm::cont::ColorSpace::DIVERGING:
{
this->UpdateExecutionColorTable(
new HandleType(static_cast<vtkm::exec::ColorTableDiverging*>(hostPortal), false));
break;
}
}
}
//transfer ColorTable and all related data
auto&& info = this->GetExecutionDataForTransfer();
if (info.NeedsTransfer)
{
bool transfered = vtkm::cont::TryExecuteOnDevice(
device, detail::transfer_color_table_to_device{}, std::move(info));
if (!transfered)
{
throwFailedRuntimeDeviceTransfer("ColorTable", device);
}
}
return this->GetExecutionHandle()->PrepareForExecution(device);
}
}
}
#endif

@ -214,83 +214,6 @@ inline vtkm::Range adjustRange(const vtkm::Range& r)
}
template <typename T>
inline vtkm::cont::ArrayHandle<T> buildSampleHandle(std::vector<T>& samples,
vtkm::Int32 numSamples,
T start,
T end,
T inc,
bool appendNanAndRangeColors)
{
int extra_values = (appendNanAndRangeColors) ? 0 : 4;
samples.reserve(static_cast<std::size_t>(numSamples + extra_values));
//Insert the below range first
if (appendNanAndRangeColors)
{
samples.push_back(std::numeric_limits<T>::lowest()); //below
}
for (T i = start; i < end; i += inc)
{
samples.push_back(i);
}
samples.push_back(end);
if (appendNanAndRangeColors)
{
//push back the last value again so that when lookups near the max value
//occur we can
samples.push_back(end);
samples.push_back(std::numeric_limits<T>::max()); //above
samples.push_back(vtkm::Nan<T>()); //nan
}
return vtkm::cont::make_ArrayHandle(samples);
}
template <typename ColorTable, typename OutputColors>
inline bool sampleColorTable(const ColorTable* self,
vtkm::Int32 numSamples,
OutputColors& colors,
double tolerance,
bool appendNanAndRangeColors)
{
vtkm::Range r = self->GetRange();
//We want the samples to start at Min, and end at Max so that means
//we want actually to interpolate numSample - 1 values. For example
//for range 0 - 1, we want the values 0, 0.5, and 1.
const double d_samples = static_cast<double>(numSamples - 1);
const double d_delta = r.Length() / d_samples;
if (r.Min > static_cast<double>(std::numeric_limits<float>::lowest()) &&
r.Max < static_cast<double>(std::numeric_limits<float>::max()))
{
//we can try and see if float space has enough resolution
const float f_samples = static_cast<float>(numSamples - 1);
const float f_start = static_cast<float>(r.Min);
const float f_delta = static_cast<float>(r.Length()) / f_samples;
const float f_end = f_delta * f_samples;
if (vtkm::Abs(static_cast<double>(f_end) - r.Max) <= tolerance &&
vtkm::Abs(static_cast<double>(f_delta) - d_delta) <= tolerance)
{
std::vector<float> samples;
auto handle =
buildSampleHandle(samples, numSamples, f_start, f_end, f_delta, appendNanAndRangeColors);
return self->Map(handle, colors);
}
}
//otherwise we need to use double space
std::vector<double> samples;
auto handle =
buildSampleHandle(samples, numSamples, r.Min, r.Max, d_delta, appendNanAndRangeColors);
return self->Map(handle, colors);
}
inline vtkm::Vec<float, 3> hsvTorgb(const vtkm::Vec<float, 3>& hsv)
{
vtkm::Vec<float, 3> rgb;

@ -30,6 +30,8 @@
#include <vtkm/worklet/DispatcherMapField.h>
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/cont/ColorTable.hxx>
#include <fstream>
#include <iostream>

@ -29,6 +29,8 @@
#include <vtkm/rendering/WorldAnnotatorGL.h>
#include <vtkm/rendering/internal/OpenGLHeaders.h>
#include <vtkm/cont/ColorTable.hxx>
namespace vtkm
{
namespace rendering

@ -20,6 +20,8 @@
#include <vtkm/rendering/Mapper.h>
#include <vtkm/cont/ColorTable.hxx>
namespace vtkm
{
namespace rendering