diff --git a/src/Image.cpp b/src/Image.cpp index 0fbe7392..a9344c3e 100644 --- a/src/Image.cpp +++ b/src/Image.cpp @@ -442,6 +442,7 @@ Image::getPrimaryImageUsageFlags() switch (this->mMemoryType) { case MemoryTypes::eDevice: case MemoryTypes::eHost: + case MemoryTypes::eDeviceAndHost: return vk::ImageUsageFlagBits::eStorage | vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst; diff --git a/src/Memory.cpp b/src/Memory.cpp index 46a7bcbd..4774c088 100644 --- a/src/Memory.cpp +++ b/src/Memory.cpp @@ -157,7 +157,8 @@ Memory::mapRawData() std::shared_ptr hostVisibleMemory = nullptr; - if (this->mMemoryType == MemoryTypes::eHost) { + if (this->mMemoryType == MemoryTypes::eHost || + this->mMemoryType == MemoryTypes::eDeviceAndHost) { hostVisibleMemory = this->mPrimaryMemory; } else if (this->mMemoryType == MemoryTypes::eDevice) { hostVisibleMemory = this->mStagingMemory; @@ -187,7 +188,8 @@ Memory::unmapRawData() std::shared_ptr hostVisibleMemory = nullptr; - if (this->mMemoryType == MemoryTypes::eHost) { + if (this->mMemoryType == MemoryTypes::eHost || + this->mMemoryType == MemoryTypes::eDeviceAndHost) { hostVisibleMemory = this->mPrimaryMemory; } else if (this->mMemoryType == MemoryTypes::eDevice) { hostVisibleMemory = this->mStagingMemory; @@ -226,6 +228,10 @@ Memory::getPrimaryMemoryPropertyFlags() return vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent; break; + case MemoryTypes::eDeviceAndHost: + return vk::MemoryPropertyFlagBits::eDeviceLocal | + vk::MemoryPropertyFlagBits::eHostVisible | + vk::MemoryPropertyFlagBits::eHostCoherent; case MemoryTypes::eStorage: return vk::MemoryPropertyFlagBits::eDeviceLocal; break; diff --git a/src/Tensor.cpp b/src/Tensor.cpp index 3553aa4e..a1eaccf2 100644 --- a/src/Tensor.cpp +++ b/src/Tensor.cpp @@ -282,12 +282,14 @@ Tensor::constructDescriptorSet(vk::DescriptorSet descriptorSet, return writeDesciptorSet; } + vk::BufferUsageFlags Tensor::getPrimaryBufferUsageFlags() { switch (this->mMemoryType) { case MemoryTypes::eDevice: case MemoryTypes::eHost: + case MemoryTypes::eDeviceAndHost: return vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst; diff --git a/src/include/kompute/Image.hpp b/src/include/kompute/Image.hpp index e15742c6..1525c4c4 100644 --- a/src/include/kompute/Image.hpp +++ b/src/include/kompute/Image.hpp @@ -120,7 +120,8 @@ class Image : public Memory "Custom data types are not supported for Kompute Images"); } - if (memoryType == MemoryTypes::eHost) { + if (memoryType == MemoryTypes::eHost || + memoryType == MemoryTypes::eDeviceAndHost) { // Host-accessible memory must be linear-tiled. tiling = vk::ImageTiling::eLinear; } else if (memoryType == MemoryTypes::eDevice || diff --git a/src/include/kompute/Memory.hpp b/src/include/kompute/Memory.hpp index 7acbb939..f179e352 100644 --- a/src/include/kompute/Memory.hpp +++ b/src/include/kompute/Memory.hpp @@ -29,6 +29,8 @@ class Memory eDevice = 0, ///< Type is device memory, source and destination eHost = 1, ///< Type is host memory, source and destination eStorage = 2, ///< Type is Device memory (only) + eDeviceAndHost = + 3, ///< Type is host-visible and host-coherent device memory }; enum class DataTypes diff --git a/test/TestOpCopyImage.cpp b/test/TestOpCopyImage.cpp index e4cc87c0..41b7568f 100644 --- a/test/TestOpCopyImage.cpp +++ b/test/TestOpCopyImage.cpp @@ -374,3 +374,27 @@ TEST(TestOpCopyImage, CopyDeviceToDeviceImage2DMismatchedSizes) EXPECT_THROW(mgr.sequence()->eval({ imageA, imageB }), std::runtime_error); } + +TEST(TestOpImageCopy, CopyDeviceAndHostToDeviceAndHostImage) +{ + kp::Manager mgr; + + std::vector testVecA{ 1, 2, 3 }; + std::vector testVecB{ 0, 0, 0 }; + + std::shared_ptr> imageA = + mgr.image(testVecA, 3, 1, 1, kp::Memory::MemoryTypes::eDeviceAndHost); + std::shared_ptr> imageB = + mgr.image(testVecB, 3, 1, 1, kp::Memory::MemoryTypes::eDeviceAndHost); + + EXPECT_TRUE(imageA->isInit()); + EXPECT_TRUE(imageB->isInit()); + + mgr.sequence() + ->eval({ imageA, imageB }) + ->eval({ imageA, imageB }) + ->eval({ imageA, imageB }); + + // Making sure the GPU holds the same vector + EXPECT_EQ(imageA->vector(), imageB->vector()); +} diff --git a/test/TestOpCopyImageToTensor.cpp b/test/TestOpCopyImageToTensor.cpp index 130b19cc..df500d12 100644 --- a/test/TestOpCopyImageToTensor.cpp +++ b/test/TestOpCopyImageToTensor.cpp @@ -212,3 +212,29 @@ TEST(TestOpCopyImageToTensor, CopyDeviceToDeviceImageUninitialised) // Making sure the GPU holds the same vector EXPECT_EQ(imageA->vector(), tensorB->vector()); } + +TEST(TestOpImageCopyToTensor, CopyDeviceAndHostToDeviceAndHostTensor) +{ + kp::Manager mgr; + + std::vector testVecA{ 1, 2, 3 }; + std::vector testVecB{ 0, 0, 0 }; + + std::shared_ptr> imageA = mgr.image( + testVecA, testVecA.size(), 1, 1, kp::Memory::MemoryTypes::eDeviceAndHost); + std::shared_ptr> tensorB = + mgr.tensor(testVecB, kp::Memory::MemoryTypes::eDeviceAndHost); + + EXPECT_TRUE(imageA->isInit()); + EXPECT_TRUE(tensorB->isInit()); + + mgr.sequence() + ->eval({ imageA }) + ->eval({ tensorB }) + ->eval({ imageA, tensorB }) + ->eval({ imageA }) + ->eval({ tensorB }); + + // Making sure the GPU holds the same vector + EXPECT_EQ(imageA->vector(), tensorB->vector()); +} diff --git a/test/TestOpCopyTensor.cpp b/test/TestOpCopyTensor.cpp index d0694f38..e9b627cc 100644 --- a/test/TestOpCopyTensor.cpp +++ b/test/TestOpCopyTensor.cpp @@ -358,3 +358,27 @@ TEST(TestOpCopyTensor, CopyTensorThroughStorageViaAlgorithmsUninitialisedOutput) // Making sure the GPU holds the same vector EXPECT_EQ(tensorIn->vector(), tensorOut->vector()); } + +TEST(TestOpTensorCopy, CopyDeviceAndHostToDeviceAndHostTensor) +{ + kp::Manager mgr; + + std::vector testVecA{ 1, 2, 3 }; + std::vector testVecB{ 0, 0, 0 }; + + std::shared_ptr> tensorA = + mgr.tensor(testVecA, kp::Memory::MemoryTypes::eDeviceAndHost); + std::shared_ptr> tensorB = + mgr.tensor(testVecB, kp::Memory::MemoryTypes::eDeviceAndHost); + + EXPECT_TRUE(tensorA->isInit()); + EXPECT_TRUE(tensorB->isInit()); + + mgr.sequence() + ->eval({ tensorA, tensorB }) + ->eval({ tensorA, tensorB }) + ->eval({ tensorA, tensorB }); + + // Making sure the GPU holds the same vector + EXPECT_EQ(tensorA->vector(), tensorB->vector()); +} diff --git a/test/TestOpCopyTensorToImage.cpp b/test/TestOpCopyTensorToImage.cpp index 85ca86ed..1b0d83a3 100644 --- a/test/TestOpCopyTensorToImage.cpp +++ b/test/TestOpCopyTensorToImage.cpp @@ -213,3 +213,29 @@ TEST(TestOpCopyTensorToImage, CopyDeviceToDeviceImageUninitialised) // Making sure the GPU holds the same vector EXPECT_EQ(tensorA->vector(), imageB->vector()); } + +TEST(TestOpTensorCopyToImage, CopyDeviceAndHostToDeviceAndHostTensor) +{ + kp::Manager mgr; + + std::vector testVecA{ 1, 2, 3 }; + std::vector testVecB{ 0, 0, 0 }; + + std::shared_ptr> tensorA = + mgr.tensor(testVecA, kp::Memory::MemoryTypes::eDeviceAndHost); + std::shared_ptr> imageB = mgr.image( + testVecB, testVecB.size(), 1, 1, kp::Memory::MemoryTypes::eDeviceAndHost); + + EXPECT_TRUE(tensorA->isInit()); + EXPECT_TRUE(imageB->isInit()); + + mgr.sequence() + ->eval({ tensorA }) + ->eval({ imageB }) + ->eval({ tensorA, imageB }) + ->eval({ tensorA }) + ->eval({ imageB }); + + // Making sure the GPU holds the same vector + EXPECT_EQ(tensorA->vector(), imageB->vector()); +} diff --git a/test/TestOpImageCreate.cpp b/test/TestOpImageCreate.cpp index 97ab3bab..611641b2 100644 --- a/test/TestOpImageCreate.cpp +++ b/test/TestOpImageCreate.cpp @@ -64,6 +64,21 @@ TEST(TestOpImageCreate, ExceptionOnInvalidTiledImage) kp::Manager mgr; + try { + std::shared_ptr> imageA = + mgr.image(testVecA, + 1, + 1, + 1, + vk::ImageTiling::eOptimal, + kp::Memory::MemoryTypes::eDeviceAndHost); + } catch (const std::runtime_error& err) { + // check exception + ASSERT_TRUE(std::string(err.what()) + .find("optimal tiling is only supported for") != + std::string::npos); + } + try { std::shared_ptr> imageA = mgr.image(testVecA,