diff --git a/src/Image.cpp b/src/Image.cpp index 32deaec9..22575583 100644 --- a/src/Image.cpp +++ b/src/Image.cpp @@ -18,13 +18,12 @@ Image::init(void* data, height, Memory::toString(this->memoryType())); - if (width == 0 || height == 0 || numChannels == 0 || dataSize == 0 || - data == nullptr) { + if (width == 0 || height == 0 || numChannels == 0) { throw std::runtime_error( "Kompute Image attempted to create a zero-sized image"); } - if (dataSize < width * height * numChannels) { + if (data != nullptr && dataSize < width * height * numChannels) { throw std::runtime_error( "Kompute Image data is smaller than the requested image size"); } @@ -48,7 +47,8 @@ Image::init(void* data, this->mTiling = tiling; this->mSize = this->mWidth * this->mHeight * this->mNumChannels; - this->rebuild(data); + this->reserve(); + this->updateRawData(data); } Image::~Image() @@ -64,12 +64,9 @@ Image::~Image() } void -Image::rebuild(void* data) +Image::reserve() { - KP_LOG_DEBUG("Kompute Image rebuilding with size {} x {} with {} channels", - this->mWidth, - this->mHeight, - this->mNumChannels); + KP_LOG_DEBUG("Reserving {} bytes for memory", this->mSize * this->mDataTypeMemorySize); if (this->mPrimaryImage || this->mPrimaryMemory) { KP_LOG_DEBUG( @@ -78,7 +75,6 @@ Image::rebuild(void* data) } this->allocateMemoryCreateGPUResources(); - this->updateRawData(data); } bool diff --git a/src/Memory.cpp b/src/Memory.cpp index 7d8f49b3..b458c3ad 100644 --- a/src/Memory.cpp +++ b/src/Memory.cpp @@ -200,7 +200,7 @@ Memory::unmapRawData() void Memory::updateRawData(void* data) { - if (this->memoryType() != Memory::MemoryTypes::eStorage) { + if (this->memoryType() != Memory::MemoryTypes::eStorage && data != nullptr) { this->mapRawData(); memcpy(this->mRawData, data, this->memorySize()); } diff --git a/src/Tensor.cpp b/src/Tensor.cpp index 61883870..6794794e 100644 --- a/src/Tensor.cpp +++ b/src/Tensor.cpp @@ -15,6 +15,8 @@ Tensor::Tensor(std::shared_ptr physicalDevice, : Memory(physicalDevice, device, dataType, memoryType) { this->mSize = elementTotalCount; + + // This is required if dataType is eCustom this->mDataTypeMemorySize = elementMemorySize; KP_LOG_DEBUG("Kompute Tensor constructor data length: {}, and type: {}", @@ -23,7 +25,30 @@ Tensor::Tensor(std::shared_ptr physicalDevice, this->mDescriptorType = vk::DescriptorType::eStorageBuffer; - this->rebuild(data); + this->reserve(); + this->updateRawData(data); +} + +Tensor::Tensor(std::shared_ptr physicalDevice, + std::shared_ptr device, + uint32_t elementTotalCount, + uint32_t elementMemorySize, + const DataTypes& dataType, + const MemoryTypes& memoryType) + : Memory(physicalDevice, device, dataType, memoryType) +{ + this->mSize = elementTotalCount; + + // This is required if dataType is eCustom + this->mDataTypeMemorySize = elementMemorySize; + + KP_LOG_DEBUG("Kompute Tensor constructor data length: {}, and type: {}", + elementTotalCount, + Memory::toString(memoryType)); + + this->mDescriptorType = vk::DescriptorType::eStorageBuffer; + + this->reserve(); } Tensor::~Tensor() @@ -39,9 +64,9 @@ Tensor::~Tensor() } void -Tensor::rebuild(void* data) +Tensor::reserve() { - KP_LOG_DEBUG("Kompute Tensor rebuilding with size {}", this->mSize); + KP_LOG_DEBUG("Reserving {} bytes for memory", this->mSize * this->mDataTypeMemorySize); if (this->mPrimaryBuffer || this->mPrimaryMemory) { KP_LOG_DEBUG( @@ -50,7 +75,6 @@ Tensor::rebuild(void* data) } this->allocateMemoryCreateGPUResources(); - this->updateRawData(data); } bool diff --git a/src/include/kompute/Image.hpp b/src/include/kompute/Image.hpp index ee1a469a..907e1bed 100644 --- a/src/include/kompute/Image.hpp +++ b/src/include/kompute/Image.hpp @@ -50,6 +50,38 @@ class Image : public Memory init(data, dataSize, width, height, numChannels, tiling); } + /** + * Constructor with no data provided. + * + * @param physicalDevice The physical device to use to fetch properties + * @param device The device to use to create the image and memory from + * @param width Width of the image in pixels + * @param height Height of the image in pixels + * @param dataType Data type for the image which is of type ImageDataTypes + * @param memoryType Type for the image which is of type MemoryTypes + * @param tiling Tiling mode to use for the image. + */ + Image(std::shared_ptr physicalDevice, + std::shared_ptr device, + uint32_t width, + uint32_t height, + uint32_t numChannels, + const DataTypes& dataType, + vk::ImageTiling tiling, + const MemoryTypes& memoryType = MemoryTypes::eDevice) + : Image(physicalDevice, + device, + nullptr, + 0, + width, + height, + numChannels, + dataType, + tiling, + memoryType) + { + } + /** * Constructor with data provided which would be used to create the * respective vulkan image and memory. No tiling has been provided @@ -92,18 +124,40 @@ class Image : public Memory } /** - * Destructor which is in charge of freeing vulkan resources unless they - * have been provided externally. + * Constructor with no data provided. No tiling has been provided + * so will be inferred from \p memoryType. + * + * @param physicalDevice The physical device to use to fetch properties + * @param device The device to use to create the image and memory from + * @param width Width of the image in pixels + * @param height Height of the image in pixels + * @param dataType Data type for the image which is of type ImageDataTypes + * @param memoryType Type for the image which is of type MemoryTypes */ - virtual ~Image(); + Image(std::shared_ptr physicalDevice, + std::shared_ptr device, + uint32_t width, + uint32_t height, + uint32_t numChannels, + const DataTypes& dataType, + const MemoryTypes& memoryType = MemoryTypes::eDevice) + : Image(physicalDevice, + device, + nullptr, + 0, + width, + height, + numChannels, + dataType, + memoryType) + { + } /** - * Function to trigger reinitialisation of the image and memory with - * new data . - * - * @param data Vector of data to use to initialise image from + * Destructor which is in charge of freeing vulkan resources unless they + * have been provided externally. */ - void rebuild(void* data); + virtual ~Image(); /** * Destroys and frees the GPU resources which include the image and memory. @@ -282,6 +336,12 @@ class Image : public Memory uint32_t height, uint32_t numChannels, vk::ImageTiling tiling); + + /** + * Function to reserve memory on the image. This does not copy any data, it + * just reserves memory, similarly to std::vector reserve() method. + */ + void reserve(); }; template @@ -304,7 +364,7 @@ class ImageT : public Image width, height, numChannels, - this->dataType(), + Memory::dataType(), tiling, imageType) { @@ -330,7 +390,7 @@ class ImageT : public Image width, height, numChannels, - this->dataType(), + Memory::dataType(), imageType) { KP_LOG_DEBUG("Kompute imageT constructor with data size {}, width {}, " @@ -341,6 +401,50 @@ class ImageT : public Image numChannels); } + ImageT(std::shared_ptr physicalDevice, + std::shared_ptr device, + uint32_t width, + uint32_t height, + uint32_t numChannels, + vk::ImageTiling tiling, + const MemoryTypes& imageType = MemoryTypes::eDevice) + : Image(physicalDevice, + device, + width, + height, + numChannels, + Memory::dataType(), + tiling, + imageType) + { + KP_LOG_DEBUG("Kompute imageT constructor with no data, width {}, " + "height {}, and num channels {}", + width, + height, + numChannels); + } + + ImageT(std::shared_ptr physicalDevice, + std::shared_ptr device, + uint32_t width, + uint32_t height, + uint32_t numChannels, + const MemoryTypes& imageType = MemoryTypes::eDevice) + : Image(physicalDevice, + device, + width, + height, + numChannels, + Memory::dataType(), + imageType) + { + KP_LOG_DEBUG("Kompute imageT constructor with no data, width {}, " + "height {}, and num channels {}", + width, + height, + numChannels); + } + ~ImageT() { KP_LOG_DEBUG("Kompute imageT destructor"); } std::vector vector() { return Memory::vector(); } diff --git a/src/include/kompute/Manager.hpp b/src/include/kompute/Manager.hpp index 06a8be98..3d7a9f17 100644 --- a/src/include/kompute/Manager.hpp +++ b/src/include/kompute/Manager.hpp @@ -96,6 +96,30 @@ class Manager return tensor; } + /** + * Create a managed tensor that will be destroyed by this manager + * if it hasn't been destroyed by its reference count going to zero. + * + * @param size The number of element in this tensor + * @param tensorType The type of tensor to initialize + * @returns Shared pointer with initialised tensor + */ + template + std::shared_ptr> tensorT( + size_t size, + Tensor::MemoryTypes tensorType = Tensor::MemoryTypes::eDevice) + { + KP_LOG_DEBUG("Kompute Manager tensor creation triggered"); + + std::shared_ptr> tensor{ new kp::TensorT( + this->mPhysicalDevice, this->mDevice, size, tensorType) }; + + if (this->mManageResources) { + this->mManagedTensors.push_back(tensor); + } + + return tensor; + } std::shared_ptr> tensor( const std::vector& data, Memory::MemoryTypes tensorType = Memory::MemoryTypes::eDevice) @@ -125,6 +149,26 @@ class Manager return tensor; } + std::shared_ptr tensor( + uint32_t elementTotalCount, + uint32_t elementMemorySize, + const Memory::DataTypes& dataType, + Memory::MemoryTypes tensorType = Memory::MemoryTypes::eDevice) + { + std::shared_ptr tensor{ new kp::Tensor(this->mPhysicalDevice, + this->mDevice, + elementTotalCount, + elementMemorySize, + dataType, + tensorType) }; + + if (this->mManageResources) { + this->mManagedTensors.push_back(tensor); + } + + return tensor; + } + /** * Create a managed image that will be destroyed by this manager * if it hasn't been destroyed by its reference count going to zero. @@ -187,6 +231,55 @@ class Manager return image; } + template + std::shared_ptr> imageT( + uint32_t width, + uint32_t height, + uint32_t numChannels, + vk::ImageTiling tiling, + Image::MemoryTypes imageType = Image::MemoryTypes::eDevice) + { + KP_LOG_DEBUG("Kompute Manager image creation triggered"); + + std::shared_ptr> image{ new kp::ImageT( + this->mPhysicalDevice, + this->mDevice, + width, + height, + numChannels, + tiling, + imageType) }; + + if (this->mManageResources) { + this->mManagedImages.push_back(image); + } + + return image; + } + + template + std::shared_ptr> imageT( + uint32_t width, + uint32_t height, + uint32_t numChannels, + Image::MemoryTypes imageType = Image::MemoryTypes::eDevice) + { + KP_LOG_DEBUG("Kompute Manager image creation triggered"); + + std::shared_ptr> image{ new kp::ImageT( + this->mPhysicalDevice, + this->mDevice, + width, + height, + numChannels, + imageType) }; + + if (this->mManageResources) { + this->mManagedImages.push_back(image); + } + + return image; + } std::shared_ptr> image( const std::vector& data, uint32_t width, @@ -209,6 +302,26 @@ class Manager return this->imageT(data, width, height, numChannels, imageType); } + std::shared_ptr> image( + uint32_t width, + uint32_t height, + uint32_t numChannels, + vk::ImageTiling tiling, + Image::MemoryTypes imageType = Image::MemoryTypes::eDevice) + { + return this->imageT( + width, height, numChannels, tiling, imageType); + } + + std::shared_ptr> image( + uint32_t width, + uint32_t height, + uint32_t numChannels, + Image::MemoryTypes imageType = Image::MemoryTypes::eDevice) + { + return this->imageT(width, height, numChannels, imageType); + } + std::shared_ptr image( void* data, size_t dataSize, @@ -263,6 +376,53 @@ class Manager return image; } + std::shared_ptr image( + uint32_t width, + uint32_t height, + uint32_t numChannels, + const Memory::DataTypes& dataType, + vk::ImageTiling tiling, + Image::MemoryTypes imageType = Image::MemoryTypes::eDevice) + { + std::shared_ptr image{ new kp::Image(this->mPhysicalDevice, + this->mDevice, + width, + height, + numChannels, + dataType, + tiling, + imageType) }; + + if (this->mManageResources) { + this->mManagedImages.push_back(image); + } + + return image; + } + + std::shared_ptr image( + uint32_t width, + uint32_t height, + uint32_t numChannels, + const Memory::DataTypes& dataType, + Image::MemoryTypes imageType = Image::MemoryTypes::eDevice) + { + std::shared_ptr image{ new kp::Image(this->mPhysicalDevice, + this->mDevice, + width, + height, + numChannels, + dataType, + imageType) }; + + if (this->mManageResources) { + this->mManagedImages.push_back(image); + } + + return image; + } + + /** * Default non-template function that can be used to create algorithm * objects which provides default types to the push and spec constants as diff --git a/src/include/kompute/Memory.hpp b/src/include/kompute/Memory.hpp index 6dc11df3..dc69b2f1 100644 --- a/src/include/kompute/Memory.hpp +++ b/src/include/kompute/Memory.hpp @@ -292,14 +292,6 @@ class Memory void mapRawData(); void unmapRawData(); void updateRawData(void* data); - - /** - * Function to trigger reinitialisation of the tensor/image buffer and - * memory with new data - * - * @param data Data to use to initialise the tensor/image from - */ - virtual void rebuild(void* data) = 0; }; } // End namespace kp diff --git a/src/include/kompute/Tensor.hpp b/src/include/kompute/Tensor.hpp index f102aa03..5ac09acb 100644 --- a/src/include/kompute/Tensor.hpp +++ b/src/include/kompute/Tensor.hpp @@ -41,18 +41,27 @@ class Tensor : public Memory const MemoryTypes& tensorType = MemoryTypes::eDevice); /** - * Destructor which is in charge of freeing vulkan resources unless they - * have been provided externally. + * Constructor with size provided which would be used to create the + * respective vulkan buffer and memory. Data is not copied. + * + * @param physicalDevice The physical device to use to fetch properties + * @param device The device to use to create the buffer and memory from + * @param elmentTotalCount the number of elements of the array + * @param elementMemorySize the size of the element + * @param tensorTypes Type for the tensor which is of type TensorTypes */ - virtual ~Tensor(); + Tensor(std::shared_ptr physicalDevice, + std::shared_ptr device, + uint32_t elementTotalCount, + uint32_t elementMemorySize, + const DataTypes& dataType, + const MemoryTypes& memoryType = MemoryTypes::eDevice); /** - * Function to trigger reinitialisation of the tensor buffer and memory with - * new data. - * - * @param data Vector of data to use to initialise tensor from + * Destructor which is in charge of freeing vulkan resources unless they + * have been provided externally. */ - void rebuild(void* data); + virtual ~Tensor(); /** * Destroys and frees the GPU resources which include the buffer and memory. @@ -193,12 +202,32 @@ class Tensor : public Memory vk::MemoryPropertyFlags getStagingMemoryPropertyFlags(); vk::DescriptorBufferInfo constructDescriptorBufferInfo(); + + /** + * Function to reserve memory on the tensor. This does not copy any data, it + * just reserves memory, similarly to std::vector reserve() method. + */ + void reserve(); }; template class TensorT : public Tensor { public: + TensorT(std::shared_ptr physicalDevice, + std::shared_ptr device, + const size_t size, + const MemoryTypes& tensorType = MemoryTypes::eDevice) + : Tensor(physicalDevice, + device, + size, + sizeof(T), + this->dataType(), + tensorType) + { + KP_LOG_DEBUG("Kompute TensorT constructor with data size {}", size); + } + TensorT( std::shared_ptr physicalDevice, std::shared_ptr device, @@ -212,7 +241,7 @@ class TensorT : public Tensor Memory::dataType(), tensorType) { - KP_LOG_DEBUG("Kompute TensorT constructor with data size {}", + KP_LOG_DEBUG("Kompute TensorT filling constructor with data size {}", data.size()); } diff --git a/test/TestImage.cpp b/test/TestImage.cpp index 19a1541a..04fdf014 100644 --- a/test/TestImage.cpp +++ b/test/TestImage.cpp @@ -15,6 +15,29 @@ TEST(TestImage, ConstructorData) EXPECT_EQ(image->vector(), vec); } +TEST(TestImage, ConstructorNoData) +{ + kp::Manager mgr; + + std::shared_ptr image = + mgr.image(nullptr, 0, 3, 3, 1, kp::Memory::DataTypes::eFloat); + EXPECT_EQ(image->size(), 9); + EXPECT_EQ(image->dataTypeMemorySize(), sizeof(float)); + + std::shared_ptr image2 = + mgr.image(3, 3, 1, kp::Memory::DataTypes::eFloat); + EXPECT_EQ(image2->size(), 9); + EXPECT_EQ(image2->dataTypeMemorySize(), sizeof(float)); + + std::shared_ptr> image3 = mgr.imageT(3, 3, 1); + EXPECT_EQ(image3->size(), 9); + EXPECT_EQ(image3->dataTypeMemorySize(), sizeof(float)); + + std::shared_ptr> image4 = mgr.image(3, 3, 1); + EXPECT_EQ(image4->size(), 9); + EXPECT_EQ(image4->dataTypeMemorySize(), sizeof(float)); +} + TEST(TestImage, DataTypes) { kp::Manager mgr; @@ -110,4 +133,4 @@ TEST(TestImage, InvalidNumberOfChannels) // There should be between 1 and 4 channels. EXPECT_THROW(mgr.image(vec, 3, 3, 0), std::runtime_error); EXPECT_THROW(mgr.image(vec, 3, 3, 5), std::runtime_error); -} \ No newline at end of file +} diff --git a/test/TestOpImageCopy.cpp b/test/TestOpImageCopy.cpp index 05b8d256..a68dc037 100644 --- a/test/TestOpImageCopy.cpp +++ b/test/TestOpImageCopy.cpp @@ -236,6 +236,89 @@ TEST(TestOpImageCopy, CopyImageThroughStorageViaAlgorithms) // Image storage requires a vector to be passed only to reflect size std::shared_ptr tensorStorage = mgr.image({ 0, 0, 0 }, 3, 1, 1, kp::Memory::MemoryTypes::eStorage); + EXPECT_TRUE(ImageIn->isInit()); + EXPECT_TRUE(ImageOut->isInit()); + + // Copy to storage tensor through algorithm + std::string shaderA = (R"( + #version 450 + + layout (local_size_x = 1) in; + + // The input tensors bind index is relative to index in parameter passed + layout(set = 0, binding = 0, r32f) uniform image2D image_in; + layout(set = 0, binding = 1, r32f) uniform image2D image_out; + + void main() { + uint index = gl_GlobalInvocationID.x; + imageStore(image_out, ivec2(index, 0), imageLoad(image_in, ivec2(index, 0))) ; + } + )"); + + auto algoA = + mgr.algorithm({ ImageIn, tensorStorage }, compileSource(shaderA)); + + // Copy from storage tensor to output tensor + std::string shaderB = (R"( + #version 450 + + layout (local_size_x = 1) in; + + // The input tensors bind index is relative to index in parameter passed + layout(set = 0, binding = 0, r32f) uniform image2D image_in; + layout(set = 0, binding = 1, r32f) uniform image2D image_out; + + void main() { + uint index = gl_GlobalInvocationID.x; + imageStore(image_out, ivec2(index, 0), imageLoad(image_in, ivec2(index, 0))) ; + } + )"); + + auto algoB = + mgr.algorithm({ tensorStorage, ImageOut }, compileSource(shaderB)); + + mgr.sequence() + ->eval({ ImageIn }) + ->eval(algoA) + ->eval(algoB) + ->eval({ ImageOut }); + + // Making sure the GPU holds the same vector + EXPECT_EQ(ImageIn->vector(), ImageOut->vector()); +} + +TEST(TestOpImageCopy, CopyDeviceToDeviceImageUninitialised) +{ + kp::Manager mgr; + + std::vector testVecA{ 1, 2, 3 }; + + std::shared_ptr imageA = mgr.image(testVecA, 3, 1, 1); + std::shared_ptr imageB = mgr.image(3, 1, 1); + + 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()); +} + +TEST(TestOpImageCopy, CopyImageThroughStorageViaAlgorithmsUninitialisedOutput) +{ + kp::Manager mgr; + + std::vector testVecIn{ 9, 1, 3 }; + + std::shared_ptr ImageIn = mgr.image(testVecIn, 3, 1, 1); + std::shared_ptr ImageOut = mgr.imageT(3, 1, 1); + + std::shared_ptr tensorStorage = + mgr.image(3, 1, 1, kp::Memory::MemoryTypes::eStorage); EXPECT_TRUE(ImageIn->isInit()); EXPECT_TRUE(ImageOut->isInit()); diff --git a/test/TestOpImageCopyToTensor.cpp b/test/TestOpImageCopyToTensor.cpp index a8342dbe..a8f95e7e 100644 --- a/test/TestOpImageCopyToTensor.cpp +++ b/test/TestOpImageCopyToTensor.cpp @@ -224,3 +224,29 @@ TEST(TestOpImageCopyToTensor, CopyThroughStorageTensor) // Making sure the GPU holds the same vector EXPECT_EQ(imageIn->vector(), tensorOut->vector()); } + +TEST(TestOpImageCopyToTensor, CopyDeviceToDeviceImageUninitialised) +{ + kp::Manager mgr; + + std::vector testVecA{ 1, 2, 3 }; + + std::shared_ptr imageA = + mgr.image(testVecA, testVecA.size(), 1, 1); + std::shared_ptr tensorB = mgr.tensorT(testVecA.size()); + + 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/TestOpTensorCopy.cpp b/test/TestOpTensorCopy.cpp index 4b4268d7..ce6b062a 100644 --- a/test/TestOpTensorCopy.cpp +++ b/test/TestOpTensorCopy.cpp @@ -173,6 +173,7 @@ TEST(TestOpImageCopy, ImageShouldFail) EXPECT_THROW(mgr.sequence()->eval({ tensor, image }), std::runtime_error); } + TEST(TestOpTensorCopy, CopyThroughStorageTensor) { kp::Manager mgr; @@ -208,6 +209,90 @@ TEST(TestOpTensorCopy, CopyTensorThroughStorageViaAlgorithms) // Tensor storage requires a vector to be passed only to reflect size std::shared_ptr> tensorStorage = mgr.tensor({ 0, 0, 0 }, kp::Memory::MemoryTypes::eStorage); + EXPECT_TRUE(tensorIn->isInit()); + EXPECT_TRUE(tensorOut->isInit()); + + // Copy to storage tensor through algorithm + std::string shaderA = (R"( + #version 450 + + layout (local_size_x = 1) in; + + // The input tensors bind index is relative to index in parameter passed + layout(set = 0, binding = 0) buffer buf_in { float t_in[]; }; + layout(set = 0, binding = 1) buffer buf_st { float t_st[]; }; + + void main() { + uint index = gl_GlobalInvocationID.x; + t_st[index] = t_in[index]; + } + )"); + + auto algoA = + mgr.algorithm({ tensorIn, tensorStorage }, compileSource(shaderA)); + + // Copy from storage tensor to output tensor + std::string shaderB = (R"( + #version 450 + + layout (local_size_x = 1) in; + + // The input tensors bind index is relative to index in parameter passed + layout(set = 0, binding = 0) buffer buf_st { float t_st[]; }; + layout(set = 0, binding = 1) buffer buf_out { float t_out[]; }; + + void main() { + uint index = gl_GlobalInvocationID.x; + t_out[index] = t_st[index]; + } + )"); + + auto algoB = + mgr.algorithm({ tensorStorage, tensorOut }, compileSource(shaderB)); + + mgr.sequence() + ->eval({ tensorIn }) + ->eval(algoA) + ->eval(algoB) + ->eval({ tensorOut }); + + // Making sure the GPU holds the same vector + EXPECT_EQ(tensorIn->vector(), tensorOut->vector()); +} + +TEST(TestOpTensorCopy, CopyDeviceToDeviceTensorUninitialised) +{ + kp::Manager mgr; + + std::vector testVecA{ 1, 2, 3 }; + + std::shared_ptr tensorA = mgr.tensor(testVecA); + std::shared_ptr tensorB = mgr.tensorT(testVecA.size()); + + 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()); +} + +TEST(TestOpTensorCopy, CopyTensorThroughStorageViaAlgorithmsUninitialisedOutput) +{ + kp::Manager mgr; + + std::vector testVecIn{ 9, 1, 3 }; + + std::shared_ptr tensorIn = mgr.tensor(testVecIn); + std::shared_ptr tensorOut = + mgr.tensorT(testVecIn.size()); + // Tensor storage requires a vector to be passed only to reflect size + std::shared_ptr tensorStorage = + mgr.tensorT(testVecIn.size(), kp::Memory::MemoryTypes::eStorage); EXPECT_TRUE(tensorIn->isInit()); EXPECT_TRUE(tensorOut->isInit()); diff --git a/test/TestOpTensorCopyToImage.cpp b/test/TestOpTensorCopyToImage.cpp index 855c3e3b..2f4c93f8 100644 --- a/test/TestOpTensorCopyToImage.cpp +++ b/test/TestOpTensorCopyToImage.cpp @@ -225,3 +225,29 @@ TEST(TestOpTensorCopyToImage, CopyThroughStorageTensor) // Making sure the GPU holds the same vector EXPECT_EQ(tensorIn->vector(), imageOut->vector()); } + +TEST(TestOpTensorCopyToImage, CopyDeviceToDeviceImageUninitialised) +{ + kp::Manager mgr; + + std::vector testVecA{ 1, 2, 3 }; + + std::shared_ptr tensorA = mgr.tensor(testVecA); + std::shared_ptr imageB = + mgr.imageT(testVecA.size(), 1, 1); + + 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/TestTensor.cpp b/test/TestTensor.cpp index 52d823ce..b5989e2d 100644 --- a/test/TestTensor.cpp +++ b/test/TestTensor.cpp @@ -15,6 +15,32 @@ TEST(TestTensor, ConstructorData) EXPECT_EQ(tensor->vector(), vec); } +TEST(TestTensor, ConstructorNoData) +{ + kp::Manager mgr; + std::shared_ptr tensor = mgr.tensor( + nullptr, 3, sizeof(float), kp::Memory::DataTypes::eFloat); + EXPECT_EQ(tensor->size(), 3); + EXPECT_EQ(tensor->dataTypeMemorySize(), sizeof(float)); + + std::shared_ptr tensor2 = + mgr.tensor(3, sizeof(float), kp::Memory::DataTypes::eFloat); + EXPECT_EQ(tensor2->size(), 3); + EXPECT_EQ(tensor2->dataTypeMemorySize(), sizeof(float)); + + std::shared_ptr> tensor3 = mgr.tensorT(3); + EXPECT_EQ(tensor3->size(), 3); + EXPECT_EQ(tensor3->dataTypeMemorySize(), sizeof(float)); +} + +TEST(TestTensor, ReserveData) +{ + kp::Manager mgr; + std::shared_ptr tensor = mgr.tensor(3, sizeof(uint32_t), kp::Memory::DataTypes::eUnsignedInt); + EXPECT_EQ(tensor->size(), 0); + EXPECT_EQ(tensor->dataTypeMemorySize(), sizeof(uint32_t)); +} + TEST(TestTensor, DataTypes) { kp::Manager mgr;