diff --git a/examples/array_multiplication/CMakeLists.txt b/examples/array_multiplication/CMakeLists.txt index 0b648382e..bfc4c1c79 100644 --- a/examples/array_multiplication/CMakeLists.txt +++ b/examples/array_multiplication/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.17.0) +cmake_minimum_required(VERSION 3.4.1) project(kompute_array_mult VERSION 0.1.0) set(CMAKE_CXX_STANDARD 14) @@ -23,10 +23,6 @@ endif() find_package(Vulkan REQUIRED) -if(KOMPUTE_OPT_ENABLE_SPDLOG) - find_package(spdlog REQUIRED) -endif() - add_executable(kompute_array_mult src/Main.cpp) diff --git a/examples/array_multiplication/README.md b/examples/array_multiplication/README.md index 931c7d639..d4082c713 100644 --- a/examples/array_multiplication/README.md +++ b/examples/array_multiplication/README.md @@ -15,8 +15,11 @@ This project has the option to either import the Kompute dependency relative to To build you just need to run the cmake command in this folder as follows: ``` -cmake \ - -Bbuild +cmake -Bbuild/ \ + -DCMAKE_BUILD_TYPE=Debug \ + -DKOMPUTE_OPT_INSTALL=0 \ + -DKOMPUTE_OPT_REPO_SUBMODULE_BUILD=1 \ + -DKOMPUTE_OPT_ENABLE_SPDLOG=1 ``` You can pass the following optional parameters based on your desired configuration: diff --git a/examples/array_multiplication/src/Main.cpp b/examples/array_multiplication/src/Main.cpp index acb76898c..dacc67f89 100755 --- a/examples/array_multiplication/src/Main.cpp +++ b/examples/array_multiplication/src/Main.cpp @@ -7,16 +7,11 @@ int main() { -#if KOMPUTE_ENABLE_SPDLOG - spdlog::set_level( - static_cast(SPDLOG_ACTIVE_LEVEL)); -#endif - kp::Manager mgr; - auto tensorInA = mgr.tensor({ 2.0, 4.0, 6.0 }); - auto tensorInB = mgr.tensor({ 0.0, 1.0, 2.0 }); - auto tensorOut = mgr.tensor({ 0.0, 0.0, 0.0 }); + auto tensorInA = mgr.tensor({ 2.0, 4.0, 6.0 }); + auto tensorInB = mgr.tensor({ 0.0, 1.0, 2.0 }); + auto tensorOut = mgr.tensor({ 0.0, 0.0, 0.0 }); std::string shader(R"( // The version to use diff --git a/examples/logistic_regression/CMakeLists.txt b/examples/logistic_regression/CMakeLists.txt index f918bbf21..8c8e0eb8f 100644 --- a/examples/logistic_regression/CMakeLists.txt +++ b/examples/logistic_regression/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.17.0) +cmake_minimum_required(VERSION 3.4.1) project(kompute_linear_reg VERSION 0.1.0) set(CMAKE_CXX_STANDARD 14) @@ -23,10 +23,6 @@ endif() find_package(Vulkan REQUIRED) -if(KOMPUTE_OPT_ENABLE_SPDLOG) - find_package(spdlog REQUIRED) -endif() - add_executable(kompute_linear_reg src/Main.cpp) @@ -39,7 +35,7 @@ include_directories( ../../single_include/) if(KOMPUTE_OPT_ENABLE_SPDLOG) - target_link_libraries(kompute_array_mult + target_link_libraries(kompute_linear_reg spdlog::spdlog) endif() diff --git a/examples/logistic_regression/README.md b/examples/logistic_regression/README.md index 0de7ee30a..342bbfca1 100644 --- a/examples/logistic_regression/README.md +++ b/examples/logistic_regression/README.md @@ -15,8 +15,11 @@ This project has the option to either import the Kompute dependency relative to To build you just need to run the cmake command in this folder as follows: ``` -cmake \ - -Bbuild +cmake -Bbuild/ \ + -DCMAKE_BUILD_TYPE=Debug \ + -DKOMPUTE_OPT_INSTALL=0 \ + -DKOMPUTE_OPT_REPO_SUBMODULE_BUILD=1 \ + -DKOMPUTE_OPT_ENABLE_SPDLOG=1 ``` You can pass the following optional parameters based on your desired configuration: diff --git a/examples/logistic_regression/src/Main.cpp b/examples/logistic_regression/src/Main.cpp index c435575e2..3b6ec11e1 100755 --- a/examples/logistic_regression/src/Main.cpp +++ b/examples/logistic_regression/src/Main.cpp @@ -17,19 +17,19 @@ int main() kp::Manager mgr; - std::shared_ptr xI = mgr.tensor({ 0, 1, 1, 1, 1 }); - std::shared_ptr xJ = mgr.tensor({ 0, 0, 0, 1, 1 }); + auto xI = mgr.tensor({ 0, 1, 1, 1, 1 }); + auto xJ = mgr.tensor({ 0, 0, 0, 1, 1 }); - std::shared_ptr y = mgr.tensor({ 0, 0, 0, 1, 1 }); + auto y = mgr.tensor({ 0, 0, 0, 1, 1 }); - std::shared_ptr wIn = mgr.tensor({ 0.001, 0.001 }); - std::shared_ptr wOutI = mgr.tensor({ 0, 0, 0, 0, 0 }); - std::shared_ptr wOutJ = mgr.tensor({ 0, 0, 0, 0, 0 }); + auto wIn = mgr.tensor({ 0.001, 0.001 }); + auto wOutI = mgr.tensor({ 0, 0, 0, 0, 0 }); + auto wOutJ = mgr.tensor({ 0, 0, 0, 0, 0 }); - std::shared_ptr bIn = mgr.tensor({ 0 }); - std::shared_ptr bOut = mgr.tensor({ 0, 0, 0, 0, 0 }); + auto bIn = mgr.tensor({ 0 }); + auto bOut = mgr.tensor({ 0, 0, 0, 0, 0 }); - std::shared_ptr lOut = mgr.tensor({ 0, 0, 0, 0, 0 }); + auto lOut = mgr.tensor({ 0, 0, 0, 0, 0 }); std::vector> params = { xI, xJ, y, wIn, wOutI, wOutJ, diff --git a/single_include/kompute/Kompute.hpp b/single_include/kompute/Kompute.hpp index 593390dbe..41e9434f8 100755 --- a/single_include/kompute/Kompute.hpp +++ b/single_include/kompute/Kompute.hpp @@ -762,7 +762,7 @@ class Shader * GLSL compiler * @return The compiled SPIR-V binary in unsigned int32 format */ - static std::vector compileSources( + static std::vector compile_sources( const std::vector& sources, const std::vector& files = {}, const std::string& entryPoint = "main", @@ -783,7 +783,7 @@ class Shader * GLSL compiler * @return The compiled SPIR-V binary in unsigned int32 format */ - static std::vector compileSource( + static std::vector compile_source( const std::string& source, const std::string& entryPoint = "main", std::vector> definitions = {}, @@ -818,6 +818,14 @@ class Tensor eHost = 1, ///< Type is host memory, source and destination eStorage = 2, ///< Type is Device memory (only) }; + enum class TensorDataTypes + { + eBool = 0, + eInt = 1, + eUnsignedInt = 2, + eFloat = 3, + eDouble = 4, + }; /** * Constructor with data provided which would be used to create the @@ -831,14 +839,78 @@ class Tensor */ Tensor(std::shared_ptr physicalDevice, std::shared_ptr device, - const std::vector& data, + void* data, + uint32_t elementTotalCount, + uint32_t elementMemorySize, + const TensorDataTypes& dataType, const TensorTypes& tensorType = TensorTypes::eDevice); /** * Destructor which is in charge of freeing vulkan resources unless they * have been provided externally. */ - ~Tensor(); + virtual ~Tensor(); + + /** + * Returns the size/magnitude of the Tensor, which will be the total number + * of elements across all dimensions + * + * @return Unsigned integer representing the total number of elements + */ + // TODO: move to cpp + virtual uint32_t size() { + return this->mSize; + } + + // TODO: move to cpp + virtual uint32_t dataTypeMemorySize() { + return this->mDataTypeMemorySize; + } + + // TODO: move to cpp + virtual uint32_t memorySize() { + return this->mSize * this->mDataTypeMemorySize; + } + + /** + * Retrieve the underlying data type of the Tensor + * + * @return Data type of tensor of type kp::Tensor::TensorDataTypes + */ + virtual TensorDataTypes dataType() { + return this->mDataType; + } + + /** + * Maps data from the Host Visible GPU memory into the data vector. It + * requires the Tensor to be of staging type for it to work. + */ + virtual void mapDataFromHostMemory(); + /** + * Maps data from the data vector into the Host Visible GPU memory. It + * requires the tensor to be of staging type for it to work. + */ + virtual void mapDataIntoHostMemory(); + + // TODO: Decide whether this is one we prefer to have also overriden in the underlying tensorView + // TODO: move to cpp + virtual void getRawData(void* data) { + this->rawMapDataFromHostMemory(data); + } + + /** + * Sets / resets the vector data of the tensor. This function does not + * perform any copies into GPU memory and is only performed on the host. + */ + virtual void setRawData(void* data, uint32_t elementTotalCount, uint32_t elementMemorySize) { + if (elementTotalCount * elementMemorySize != this->memorySize()) { + throw std::runtime_error( + "Kompute Tensor Cannot set data of different sizes"); + } + this->mSize = elementTotalCount; + this->mDataTypeMemorySize = elementMemorySize; + this->rawMapDataIntoHostMemory(data); + } /** * Function to trigger reinitialisation of the tensor buffer and memory with @@ -847,8 +919,9 @@ class Tensor * @param data Vector of data to use to initialise vector from * @param tensorType The type to use for the tensor */ - void rebuild(const std::vector& data, - TensorTypes tensorType = TensorTypes::eDevice); + void rebuild(void* data, + uint32_t elementTotalCount, + uint32_t elementMemorySize); /** * Destroys and frees the GPU resources which include the buffer and memory. @@ -862,32 +935,6 @@ class Tensor */ bool isInit(); - /** - * Returns the vector of data currently contained by the Tensor. It is - * important to ensure that there is no out-of-sync data with the GPU - * memory. - * - * @return Reference to vector of elements representing the data in the - * tensor. - */ - std::vector& data(); - /** - * Overrides the subscript operator to expose the underlying data's - * subscript operator which in this case would be its underlying - * vector's. - * - * @param i The index where the element will be returned from. - * @return Returns the element in the position requested. - */ - float& operator[](int index); - /** - * Returns the size/magnitude of the Tensor, which will be the total number - * of elements across all dimensions - * - * @return Unsigned integer representing the total number of elements - */ - uint32_t size(); - /** * Retrieve the tensor type of the Tensor * @@ -895,12 +942,6 @@ class Tensor */ TensorTypes tensorType(); - /** - * Sets / resets the vector data of the tensor. This function does not - * perform any copies into GPU memory and is only performed on the host. - */ - void setData(const std::vector& data); - /** * Records a copy from the memory of the tensor provided to the current * thensor. This is intended to pass memory into a processing, to perform @@ -963,17 +1004,57 @@ class Tensor * @return Descriptor buffer info with own buffer */ vk::DescriptorBufferInfo constructDescriptorBufferInfo(); - /** - * Maps data from the Host Visible GPU memory into the data vector. It - * requires the Tensor to be of staging type for it to work. - */ - void mapDataFromHostMemory(); - /** - * Maps data from the data vector into the Host Visible GPU memory. It - * requires the tensor to be of staging type for it to work. - */ - void mapDataIntoHostMemory(); + protected: + void rawMapDataFromHostMemory(void* data) { + + KP_LOG_DEBUG("Kompute Tensor mapping data from host buffer"); + + std::shared_ptr hostVisibleMemory = nullptr; + + if (this->mTensorType == TensorTypes::eHost) { + hostVisibleMemory = this->mPrimaryMemory; + } else if (this->mTensorType == TensorTypes::eDevice) { + hostVisibleMemory = this->mStagingMemory; + } else { + KP_LOG_WARN( + "Kompute Tensor mapping data not supported on storage tensor"); + return; + } + + vk::DeviceSize bufferSize = this->memorySize(); + void* mapped = this->mDevice->mapMemory( + *hostVisibleMemory, 0, bufferSize, vk::MemoryMapFlags()); + vk::MappedMemoryRange mappedMemoryRange(*hostVisibleMemory, 0, bufferSize); + this->mDevice->invalidateMappedMemoryRanges(mappedMemoryRange); + memcpy(data, mapped, bufferSize); + this->mDevice->unmapMemory(*hostVisibleMemory); + } + + void rawMapDataIntoHostMemory(void* data) { + KP_LOG_DEBUG("Kompute Tensor mapping data into host buffer"); + + std::shared_ptr hostVisibleMemory = nullptr; + + if (this->mTensorType == TensorTypes::eHost) { + hostVisibleMemory = this->mPrimaryMemory; + } else if (this->mTensorType == TensorTypes::eDevice) { + hostVisibleMemory = this->mStagingMemory; + } else { + KP_LOG_WARN( + "Kompute Tensor mapping data not supported on storage tensor"); + return; + } + + vk::DeviceSize bufferSize = this->memorySize(); + + void* mapped = this->mDevice->mapMemory( + *hostVisibleMemory, 0, bufferSize, vk::MemoryMapFlags()); + memcpy(mapped, data, bufferSize); + vk::MappedMemoryRange mappedRange(*hostVisibleMemory, 0, bufferSize); + this->mDevice->flushMappedMemoryRanges(1, &mappedRange); + this->mDevice->unmapMemory(*hostVisibleMemory); + } private: // -------------- NEVER OWNED RESOURCES std::shared_ptr mPhysicalDevice; @@ -990,9 +1071,10 @@ class Tensor bool mFreeStagingMemory = false; // -------------- ALWAYS OWNED RESOURCES - std::vector mData; - - TensorTypes mTensorType = TensorTypes::eDevice; + TensorTypes mTensorType; + TensorDataTypes mDataType; + uint32_t mSize; + uint32_t mDataTypeMemorySize; void allocateMemoryCreateGPUResources(); // Creates the vulkan buffer void createBuffer(std::shared_ptr buffer, @@ -1012,9 +1094,98 @@ class Tensor vk::MemoryPropertyFlags getPrimaryMemoryPropertyFlags(); vk::BufferUsageFlags getStagingBufferUsageFlags(); vk::MemoryPropertyFlags getStagingMemoryPropertyFlags(); - uint64_t memorySize(); + }; +// TODO: Limit T to be only float, bool, double, etc +template +class TensorView: public Tensor +{ + public: + TensorView(std::shared_ptr physicalDevice, + std::shared_ptr device, + const std::vector& data, + const TensorTypes& tensorType = TensorTypes::eDevice) + : Tensor(physicalDevice, device, (void*)data.data(), data.size(), sizeof(T), this->dataType()) + { + + } + + ~TensorView() { + + } + + void rebuild(const std::vector& data, + TensorTypes tensorType = TensorTypes::eDevice) { + + this->mData = data; + Tensor::rebuild(data.data(), data.size(), sizeof(T)); + } + + std::vector& data() { + return this->mData; + } + + T& operator[](int index) { + return this->mData[index]; + } + + void setData(const std::vector& data) { + + if (data.size() != this->mData.size()) { + throw std::runtime_error( + "Kompute TensorView Cannot set data of different sizes"); + } + + this->mData = data; + + Tensor::setRawData(this->mData.data(), this->mData.size(), sizeof(T)); + } + + void setRawData(void* data, uint32_t elementTotalCount, uint32_t elementMemorySize) override + { + assert(elementMemorySize == sizeof(T)); + + this->mData = { (T*)data, ((T*)data) + elementTotalCount }; + Tensor::setRawData(this->mData.data(), this->mData.size(), sizeof(T)); + } + + TensorDataTypes dataType() override; + + uint32_t size() override { + return this->mData.size(); + } + + uint32_t memorySize() override { + return this->mData.size() * sizeof(T); + } + + /** + * Maps data from the Host Visible GPU memory into the data vector. It + * requires the Tensor to be of staging type for it to work. + */ + void mapDataFromHostMemory() override { + KP_LOG_DEBUG("Kompute TensorView mapDataFromHostMemory copying data"); + + this->rawMapDataFromHostMemory(this->mData.data()); + } + /** + * Maps data from the data vector into the Host Visible GPU memory. It + * requires the tensor to be of staging type for it to work. + */ + void mapDataIntoHostMemory() override { + KP_LOG_DEBUG("Kompute TensorView mapDataIntoHostMemory copying data"); + + this->rawMapDataIntoHostMemory(this->mData.data()); + } + + private: + // -------------- ALWAYS OWNED RESOURCES + std::vector mData; + +}; + + } // End namespace kp namespace kp { @@ -1883,9 +2054,22 @@ class Manager * @param tensorType The type of tensor to initialize * @returns Shared pointer with initialised tensor */ - std::shared_ptr tensor( - const std::vector& data, - Tensor::TensorTypes tensorType = Tensor::TensorTypes::eDevice); + template + std::shared_ptr> tensor( + const std::vector& data, + Tensor::TensorTypes tensorType = Tensor::TensorTypes::eDevice) + { + KP_LOG_DEBUG("Kompute Manager tensor creation triggered"); + + std::shared_ptr> tensor{ new kp::TensorView( + this->mPhysicalDevice, this->mDevice, data, tensorType) }; + + if (this->mManageResources) { + this->mManagedTensors.push_back(tensor); + } + + return tensor; + } /** * Create a managed algorithm that will be destroyed by this manager diff --git a/src/Manager.cpp b/src/Manager.cpp index e3bdbb2d9..5d6bf4cd4 100644 --- a/src/Manager.cpp +++ b/src/Manager.cpp @@ -395,21 +395,6 @@ Manager::createDevice(const std::vector& familyQueueIndices, KP_LOG_DEBUG("Kompute Manager compute queue obtained"); } -std::shared_ptr -Manager::tensor(const std::vector& data, Tensor::TensorTypes tensorType) -{ - KP_LOG_DEBUG("Kompute Manager tensor creation triggered"); - - std::shared_ptr tensor{ new kp::Tensor( - this->mPhysicalDevice, this->mDevice, data, tensorType) }; - - if (this->mManageResources) { - this->mManagedTensors.push_back(tensor); - } - - return tensor; -} - std::shared_ptr Manager::algorithm(const std::vector>& tensors, const std::vector& spirv, diff --git a/src/OpTensorCopy.cpp b/src/OpTensorCopy.cpp index 6950a4cd2..16e3017e9 100644 --- a/src/OpTensorCopy.cpp +++ b/src/OpTensorCopy.cpp @@ -13,6 +13,14 @@ OpTensorCopy::OpTensorCopy(const std::vector>& tensors) throw std::runtime_error( "Kompute OpTensorCopy called with less than 2 tensor"); } + + kp::Tensor::TensorDataTypes dataType = this->mTensors[0]->dataType(); + for (const std::shared_ptr& tensor : tensors) { + if (tensor->dataType() != dataType) { + throw std::runtime_error(fmt::format("Attempting to copy tensors of different types from {} to {}", + dataType, tensor->dataType())); + } + } } OpTensorCopy::~OpTensorCopy() @@ -43,9 +51,16 @@ OpTensorCopy::postEval(const vk::CommandBuffer& commandBuffer) { KP_LOG_DEBUG("Kompute OpTensorCopy postEval called"); + // TODO: Simplify with a copyRawData + uint32_t size = this->mTensors[0]->size(); + uint32_t dataTypeMemSize = this->mTensors[0]->dataTypeMemorySize(); + uint32_t memSize = size * dataTypeMemSize; + void* data = operator new(memSize); + this->mTensors[0]->getRawData(data); + // Copy the data from the first tensor into all the tensors for (size_t i = 1; i < this->mTensors.size(); i++) { - this->mTensors[i]->setData(this->mTensors[0]->data()); + this->mTensors[i]->setRawData(data, size, dataTypeMemSize); } } diff --git a/src/Tensor.cpp b/src/Tensor.cpp index dc254fe83..4f188d5af 100644 --- a/src/Tensor.cpp +++ b/src/Tensor.cpp @@ -17,8 +17,10 @@ Tensor::Tensor(std::shared_ptr physicalDevice, this->mPhysicalDevice = physicalDevice; this->mDevice = device; + this->mDataType = dataType; + this->mTensorType = tensorType; - this->rebuild(data, elementTotalCount, elementMemorySize, dataType, tensorType); + this->rebuild(data, elementTotalCount, elementMemorySize); } Tensor::~Tensor() @@ -34,16 +36,12 @@ Tensor::~Tensor() void Tensor::rebuild(void* data, uint32_t elementTotalCount, - uint32_t elementMemorySize, - const TensorDataTypes& dataType, - TensorTypes tensorType) + uint32_t elementMemorySize) { KP_LOG_DEBUG("Kompute Tensor rebuilding with size {}", elementTotalCount); this->mSize = elementTotalCount; - this->mElementMemorySize = elementMemorySize; - this->mDataType = dataType; - this->mTensorType = tensorType; + this->mDataTypeMemorySize = elementMemorySize; if (this->mPrimaryBuffer || this->mPrimaryMemory) { KP_LOG_DEBUG( @@ -439,4 +437,34 @@ Tensor::destroy() KP_LOG_DEBUG("Kompute Tensor successful destroy()"); } +template<> +Tensor::TensorDataTypes +TensorView::dataType() { + return Tensor::TensorDataTypes::eBool; +} + +template<> +Tensor::TensorDataTypes +TensorView::dataType() { + return Tensor::TensorDataTypes::eInt; +} + +template<> +Tensor::TensorDataTypes +TensorView::dataType() { + return Tensor::TensorDataTypes::eUnsignedInt; +} + +template<> +Tensor::TensorDataTypes +TensorView::dataType() { + return Tensor::TensorDataTypes::eFloat; +} + +template<> +Tensor::TensorDataTypes +TensorView::dataType() { + return Tensor::TensorDataTypes::eDouble; +} + } diff --git a/src/include/kompute/Manager.hpp b/src/include/kompute/Manager.hpp index d9c6ddf3e..d27bccacc 100644 --- a/src/include/kompute/Manager.hpp +++ b/src/include/kompute/Manager.hpp @@ -74,9 +74,22 @@ class Manager * @param tensorType The type of tensor to initialize * @returns Shared pointer with initialised tensor */ - std::shared_ptr tensor( - const std::vector& data, - Tensor::TensorTypes tensorType = Tensor::TensorTypes::eDevice); + template + std::shared_ptr> tensor( + const std::vector& data, + Tensor::TensorTypes tensorType = Tensor::TensorTypes::eDevice) + { + KP_LOG_DEBUG("Kompute Manager tensor creation triggered"); + + std::shared_ptr> tensor{ new kp::TensorView( + this->mPhysicalDevice, this->mDevice, data, tensorType) }; + + if (this->mManageResources) { + this->mManagedTensors.push_back(tensor); + } + + return tensor; + } /** * Create a managed algorithm that will be destroyed by this manager diff --git a/src/include/kompute/Tensor.hpp b/src/include/kompute/Tensor.hpp index f2583708d..03e52d43d 100644 --- a/src/include/kompute/Tensor.hpp +++ b/src/include/kompute/Tensor.hpp @@ -51,14 +51,14 @@ class Tensor void* data, uint32_t elementTotalCount, uint32_t elementMemorySize, - const TensorDataTypes& dataType = TensorDataTypes::eFloat, + const TensorDataTypes& dataType, const TensorTypes& tensorType = TensorTypes::eDevice); /** * Destructor which is in charge of freeing vulkan resources unless they * have been provided externally. */ - ~Tensor(); + virtual ~Tensor(); /** * Returns the size/magnitude of the Tensor, which will be the total number @@ -68,12 +68,17 @@ class Tensor */ // TODO: move to cpp virtual uint32_t size() { - return this->mElementMemorySize; + return this->mSize; + } + + // TODO: move to cpp + virtual uint32_t dataTypeMemorySize() { + return this->mDataTypeMemorySize; } // TODO: move to cpp virtual uint32_t memorySize() { - return this->mSize * this->mElementMemorySize; + return this->mSize * this->mDataTypeMemorySize; } /** @@ -98,10 +103,24 @@ class Tensor // TODO: Decide whether this is one we prefer to have also overriden in the underlying tensorView // TODO: move to cpp - void getRawData(void* data) { + virtual void getRawData(void* data) { this->rawMapDataFromHostMemory(data); } + /** + * Sets / resets the vector data of the tensor. This function does not + * perform any copies into GPU memory and is only performed on the host. + */ + virtual void setRawData(void* data, uint32_t elementTotalCount, uint32_t elementMemorySize) { + if (elementTotalCount * elementMemorySize != this->memorySize()) { + throw std::runtime_error( + "Kompute Tensor Cannot set data of different sizes"); + } + this->mSize = elementTotalCount; + this->mDataTypeMemorySize = elementMemorySize; + this->rawMapDataIntoHostMemory(data); + } + /** * Function to trigger reinitialisation of the tensor buffer and memory with * new data as well as new potential device type. @@ -111,9 +130,7 @@ class Tensor */ void rebuild(void* data, uint32_t elementTotalCount, - uint32_t elementMemorySize, - const TensorDataTypes& dataType = TensorDataTypes::eFloat, - TensorTypes tensorType = TensorTypes::eDevice); + uint32_t elementMemorySize); /** * Destroys and frees the GPU resources which include the buffer and memory. @@ -134,19 +151,6 @@ class Tensor */ TensorTypes tensorType(); - /** - * Sets / resets the vector data of the tensor. This function does not - * perform any copies into GPU memory and is only performed on the host. - */ - void setRawData(void* data, uint32_t elementTotalCount, uint32_t elementMemorySize) { - if (elementTotalCount * elementMemorySize != this->memorySize()) { - throw std::runtime_error( - "Kompute Tensor Cannot set data of different sizes"); - } - this->mSize = elementTotalCount; - this->mElementMemorySize = elementMemorySize; - this->rawMapDataIntoHostMemory(data); - } /** * Records a copy from the memory of the tensor provided to the current @@ -211,46 +215,7 @@ class Tensor */ vk::DescriptorBufferInfo constructDescriptorBufferInfo(); - private: - // -------------- NEVER OWNED RESOURCES - std::shared_ptr mPhysicalDevice; - std::shared_ptr mDevice; - - // -------------- OPTIONALLY OWNED RESOURCES - std::shared_ptr mPrimaryBuffer; - bool mFreePrimaryBuffer = false; - std::shared_ptr mStagingBuffer; - bool mFreeStagingBuffer = false; - std::shared_ptr mPrimaryMemory; - bool mFreePrimaryMemory = false; - std::shared_ptr mStagingMemory; - bool mFreeStagingMemory = false; - - // -------------- ALWAYS OWNED RESOURCES - TensorTypes mTensorType; - TensorDataTypes mDataType; - uint32_t mSize; - uint32_t mElementMemorySize; - - void allocateMemoryCreateGPUResources(); // Creates the vulkan buffer - void createBuffer(std::shared_ptr buffer, - vk::BufferUsageFlags bufferUsageFlags); - void allocateBindMemory(std::shared_ptr buffer, - std::shared_ptr memory, - vk::MemoryPropertyFlags memoryPropertyFlags); - void recordCopyBuffer(const vk::CommandBuffer& commandBuffer, - std::shared_ptr bufferFrom, - std::shared_ptr bufferTo, - vk::DeviceSize bufferSize, - vk::BufferCopy copyRegion, - bool createBarrier); - - // Private util functions - vk::BufferUsageFlags getPrimaryBufferUsageFlags(); - vk::MemoryPropertyFlags getPrimaryMemoryPropertyFlags(); - vk::BufferUsageFlags getStagingBufferUsageFlags(); - vk::MemoryPropertyFlags getStagingMemoryPropertyFlags(); - + protected: void rawMapDataFromHostMemory(void* data) { KP_LOG_DEBUG("Kompute Tensor mapping data from host buffer"); @@ -300,6 +265,46 @@ class Tensor this->mDevice->flushMappedMemoryRanges(1, &mappedRange); this->mDevice->unmapMemory(*hostVisibleMemory); } + private: + // -------------- NEVER OWNED RESOURCES + std::shared_ptr mPhysicalDevice; + std::shared_ptr mDevice; + + // -------------- OPTIONALLY OWNED RESOURCES + std::shared_ptr mPrimaryBuffer; + bool mFreePrimaryBuffer = false; + std::shared_ptr mStagingBuffer; + bool mFreeStagingBuffer = false; + std::shared_ptr mPrimaryMemory; + bool mFreePrimaryMemory = false; + std::shared_ptr mStagingMemory; + bool mFreeStagingMemory = false; + + // -------------- ALWAYS OWNED RESOURCES + TensorTypes mTensorType; + TensorDataTypes mDataType; + uint32_t mSize; + uint32_t mDataTypeMemorySize; + + void allocateMemoryCreateGPUResources(); // Creates the vulkan buffer + void createBuffer(std::shared_ptr buffer, + vk::BufferUsageFlags bufferUsageFlags); + void allocateBindMemory(std::shared_ptr buffer, + std::shared_ptr memory, + vk::MemoryPropertyFlags memoryPropertyFlags); + void recordCopyBuffer(const vk::CommandBuffer& commandBuffer, + std::shared_ptr bufferFrom, + std::shared_ptr bufferTo, + vk::DeviceSize bufferSize, + vk::BufferCopy copyRegion, + bool createBarrier); + + // Private util functions + vk::BufferUsageFlags getPrimaryBufferUsageFlags(); + vk::MemoryPropertyFlags getPrimaryMemoryPropertyFlags(); + vk::BufferUsageFlags getStagingBufferUsageFlags(); + vk::MemoryPropertyFlags getStagingMemoryPropertyFlags(); + }; // TODO: Limit T to be only float, bool, double, etc @@ -310,15 +315,21 @@ class TensorView: public Tensor TensorView(std::shared_ptr physicalDevice, std::shared_ptr device, const std::vector& data, - const TensorTypes& tensorType = TensorTypes::eDevice); + const TensorTypes& tensorType = TensorTypes::eDevice) + : Tensor(physicalDevice, device, (void*)data.data(), data.size(), sizeof(T), this->dataType()) + { - ~TensorView(); + } + + ~TensorView() { + + } void rebuild(const std::vector& data, TensorTypes tensorType = TensorTypes::eDevice) { this->mData = data; - Tensor::rebuild(data.data(), data.size(), sizeof(T), this->dataType(), tensorType); + Tensor::rebuild(data.data(), data.size(), sizeof(T)); } std::vector& data() { @@ -338,17 +349,25 @@ class TensorView: public Tensor this->mData = data; - this->setRawData(this->mData.data(), this->mData.size(), sizeof(T), this->dataType()); + Tensor::setRawData(this->mData.data(), this->mData.size(), sizeof(T)); + } + + void setRawData(void* data, uint32_t elementTotalCount, uint32_t elementMemorySize) override + { + assert(elementMemorySize == sizeof(T)); + + this->mData = { (T*)data, ((T*)data) + elementTotalCount }; + Tensor::setRawData(this->mData.data(), this->mData.size(), sizeof(T)); } TensorDataTypes dataType() override; uint32_t size() override { - return this->mData->size(); + return this->mData.size(); } uint32_t memorySize() override { - return this->mData->size() * sizeof(T); + return this->mData.size() * sizeof(T); } /** @@ -376,34 +395,4 @@ class TensorView: public Tensor }; -template<> -Tensor::TensorDataTypes -TensorView::dataType() { - return Tensor::TensorDataTypes::eBool; -} - -template<> -Tensor::TensorDataTypes -TensorView::dataType() { - return Tensor::TensorDataTypes::eInt; -} - -template<> -Tensor::TensorDataTypes -TensorView::dataType() { - return Tensor::TensorDataTypes::eUnsignedInt; -} - -template<> -Tensor::TensorDataTypes -TensorView::dataType() { - return Tensor::TensorDataTypes::eFloat; -} - -template<> -Tensor::TensorDataTypes -TensorView::dataType() { - return Tensor::TensorDataTypes::eDouble; -} - } // End namespace kp