From 6dc06423d8e75c1943c833ab66b95cd6d267b8db Mon Sep 17 00:00:00 2001 From: Robert Maynard Date: Thu, 12 Jul 2018 08:28:40 -0400 Subject: [PATCH] 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. --- ...al-object-handle-non-templated-transfer.md | 21 ++++++++ vtkm/cont/ColorTable.cxx | 20 +++++--- vtkm/cont/ColorTable.h | 16 ++++-- vtkm/cont/ColorTable.hxx | 9 ++-- vtkm/cont/ColorTablePrivate.hxx | 3 +- vtkm/cont/VirtualObjectHandle.h | 35 +++++++++---- vtkm/cont/testing/TestingColorTable.h | 50 ++++++++++++++++++- vtkm/exec/ColorTable.h | 10 ++-- 8 files changed, 130 insertions(+), 34 deletions(-) create mode 100644 docs/changelog/virtual-object-handle-non-templated-transfer.md diff --git a/docs/changelog/virtual-object-handle-non-templated-transfer.md b/docs/changelog/virtual-object-handle-non-templated-transfer.md new file mode 100644 index 000000000..3445fbbb1 --- /dev/null +++ b/docs/changelog/virtual-object-handle-non-templated-transfer.md @@ -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 +const BaseType* moveToDevice(VirtualObjectHandle& handle, + vtkm::cont::vtkm::cont::DeviceAdapterId deviceId) +{ + return handle.PrepareForExecution(deviceId); +} +``` diff --git a/vtkm/cont/ColorTable.cxx b/vtkm/cont/ColorTable.cxx index f8c95943d..2273029a3 100644 --- a/vtkm/cont/ColorTable.cxx +++ b/vtkm/cont/ColorTable.cxx @@ -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* 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* 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); } //--------------------------------------------------------------------------- diff --git a/vtkm/cont/ColorTable.h b/vtkm/cont/ColorTable.h index fe1d9765a..d40ba71f9 100644 --- a/vtkm/cont/ColorTable.h +++ b/vtkm/cont/ColorTable.h @@ -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* 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 + const vtkm::exec::ColorTableBase* PrepareForExecution(DeviceAdapter) const + { + auto deviceId = vtkm::cont::DeviceAdapterTraits::GetId(); + return this->PrepareForExecution(deviceId); + } /// \brief returns the modified count for the virtual object handle of the exec color table diff --git a/vtkm/cont/ColorTable.hxx b/vtkm/cont/ColorTable.hxx index 8aac53029..f108635ba 100644 --- a/vtkm/cont/ColorTable.hxx +++ b/vtkm/cont/ColorTable.hxx @@ -83,7 +83,7 @@ struct transfer_color_table_to_device template 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 bool ColorTable::Map(const vtkm::cont::ArrayHandle& values, vtkm::cont::ArrayHandle>& 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 bool ColorTable::Map(const vtkm::cont::ArrayHandle& values, vtkm::cont::ArrayHandle>& 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 diff --git a/vtkm/cont/ColorTablePrivate.hxx b/vtkm/cont/ColorTablePrivate.hxx index 70ec8d826..d6bf1677f 100644 --- a/vtkm/cont/ColorTablePrivate.hxx +++ b/vtkm/cont/ColorTablePrivate.hxx @@ -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 HostSideCache; //Execution side version of the ColorTableBase. std::unique_ptr> ExecHandle; @@ -66,6 +66,7 @@ struct ColorTableInternals vtkm::cont::ArrayHandle> OpacityMidSharpHandle; bool ColorArraysChanged = true; bool OpacityArraysChanged = true; + bool HostSideCacheChanged = true; void RecalculateRange() { diff --git a/vtkm/cont/VirtualObjectHandle.h b/vtkm/cont/VirtualObjectHandle.h index 97fad110d..53fc5a9aa 100644 --- a/vtkm/cont/VirtualObjectHandle.h +++ b/vtkm/cont/VirtualObjectHandle.h @@ -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 - VTKM_CONT const VirtualBaseType* PrepareForExecution(DeviceAdapter) const + VTKM_CONT const VirtualBaseType* PrepareForExecution(vtkm::cont::DeviceAdapterId deviceId) const { - using DeviceInfo = vtkm::cont::DeviceAdapterTraits; - 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(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 + VTKM_CONT const VirtualBaseType* PrepareForExecution(DeviceAdapter) const + { + using DeviceInfo = vtkm::cont::DeviceAdapterTraits; + return this->PrepareForExecution(DeviceInfo::GetId()); + } + private: class TransferInterface { diff --git a/vtkm/cont/testing/TestingColorTable.h b/vtkm/cont/testing/TestingColorTable.h index 012f74d42..167134132 100644 --- a/vtkm/cont/testing/TestingColorTable.h +++ b/vtkm/cont/testing/TestingColorTable.h @@ -381,6 +381,21 @@ public: VTKM_TEST_ASSERT(result == correct_hsv_values[i], "incorrect value when interpolating between values"); } + + vtkm::cont::ArrayHandle> colors_rgb; + table.SetColorSpace(vtkm::cont::ColorSpace::RGB); + table.Map(field, colors_rgb); + + const vtkm::Vec 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(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> colors; + TransferFunction transfer(table.PrepareForExecution(DeviceAdapterTag{})); + vtkm::worklet::DispatcherMapField dispatcher(transfer); + dispatcher.Invoke(samples, colors); + + const vtkm::Vec 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(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(); } diff --git a/vtkm/exec/ColorTable.h b/vtkm/exec/ColorTable.h index cd5cd67b3..f09bb60b3 100644 --- a/vtkm/exec/ColorTable.h +++ b/vtkm/exec/ColorTable.h @@ -68,7 +68,7 @@ class VTKM_ALWAYS_EXPORT ColorTableRGB final : public ColorTableBase public: inline VTKM_EXEC vtkm::Vec MapThroughColorSpace(const vtkm::Vec& rgb1, const vtkm::Vec& 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 MapThroughColorSpace(const vtkm::Vec& rgb1, const vtkm::Vec& 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 MapThroughColorSpace(const vtkm::Vec& rgb1, const vtkm::Vec& 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 MapThroughColorSpace(const vtkm::Vec& rgb1, const vtkm::Vec& 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 MapThroughColorSpace(const vtkm::Vec& rgb1, const vtkm::Vec& rgb2, - float weight) const final; + float weight) const; }; } }