From 13206a9d9bc988eee8b6bfd9ac06d16f4bf7a61c Mon Sep 17 00:00:00 2001 From: Alejandro Saucedo Date: Mon, 31 Aug 2020 09:24:33 +0100 Subject: [PATCH] Updated vulkan pipeline to support raw shaders --- Makefile | 7 ++- single_include/kompute/Kompute.hpp | 63 ++++++++++++------- src/include/kompute/operations/OpAlgoBase.hpp | 59 ++++++++++------- src/include/kompute/operations/OpMult.hpp | 4 +- test/TestCustomOpRawShaders.cpp | 36 +++++++++++ 5 files changed, 119 insertions(+), 50 deletions(-) create mode 100644 test/TestCustomOpRawShaders.cpp diff --git a/Makefile b/Makefile index d65316308..c036dbf69 100755 --- a/Makefile +++ b/Makefile @@ -10,6 +10,9 @@ VCPKG_WIN_PATH ?= "C:\\Users\\axsau\\Programming\\lib\\vcpkg\\scripts\\buildsystems\\vcpkg.cmake" VCPKG_UNIX_PATH ?= "/c/Users/axsau/Programming/lib/vcpkg/scripts/buildsystems/vcpkg.cmake" +# Regext to pass to catch2 to filter tests +FILTER_TESTS ?= "*" + ifeq ($(OS),Windows_NT) # is Windows_NT on XP, 2000, 7, Vista, 10... CMAKE_BIN ?= "C:\Program Files\CMake\bin\cmake.exe" SCMP_BIN="C:\\VulkanSDK\\1.2.141.2\\Bin32\\glslangValidator.exe" @@ -62,7 +65,7 @@ mk_run_docs: mk_build_docs (cd build/docs/sphinx && python2.7 -m SimpleHTTPServer) mk_run_tests: mk_build_tests - ./build/test/test_kompute + ./build/test/test_kompute $(FILTER_TESTS) ####### Visual studio build shortcut commands ####### @@ -91,7 +94,7 @@ vs_run_docs: vs_build_docs (cd build/docs/sphinx && python2.7 -m SimpleHTTPServer) vs_run_tests: vs_build_tests - ./build/test/Debug/test_kompute.exe + ./build/test/Debug/test_kompute.exe $(FILTER_TESTS) ####### Create release ###### diff --git a/single_include/kompute/Kompute.hpp b/single_include/kompute/Kompute.hpp index 40fb16591..a7a7bb989 100755 --- a/single_include/kompute/Kompute.hpp +++ b/single_include/kompute/Kompute.hpp @@ -838,12 +838,16 @@ class OpAlgoBase : public OpBase * @param device Vulkan logical device for passing to Algorithm * @param commandBuffer Vulkan Command Buffer to record commands into * @param tensors Tensors that are to be used in this operation + * @param copyOutputData Whether to map device data for all output tensors back to their host data vectors + * @param shaderFilePath Optional parameter to specify the shader to load (either in spirv or raw format) */ OpAlgoBase(std::shared_ptr physicalDevice, std::shared_ptr device, std::shared_ptr commandBuffer, std::vector>& tensors, - bool copyOutputData); + bool copyOutputData = false, + std::string shaderFilePath = "", + const std::vector& shaderDataRaw = {}); /** * Default destructor, which is in charge of destroying the algorithm @@ -891,7 +895,8 @@ class OpAlgoBase : public OpBase uint32_t mY; uint32_t mZ; - std::string mOptSpirvBinPath; ///< Optional member variable which can be provided for the OpAlgoBase to find the data automatically and load for processing + std::string mShaderFilePath; ///< Optional member variable which can be provided for the OpAlgoBase to find the data automatically and load for processing + std::vector mShaderDataRaw; ///< Optional member variable which can be provided to contain either the raw shader content or the spirv binary content virtual std::vector fetchSpirvBinaryData(); }; @@ -915,12 +920,12 @@ OpAlgoBase::OpAlgoBase(std::shared_ptr physicalD std::shared_ptr device, std::shared_ptr commandBuffer, std::vector>& tensors, - bool copyOutputData) + bool copyOutputData, + std::string shaderFilePath, + const std::vector& shaderDataRaw) : OpBase(physicalDevice, device, commandBuffer, tensors, false) { - SPDLOG_DEBUG("Kompute OpAlgoBase constructor with params"); - - SPDLOG_DEBUG("Kompute OpAlgoBase configured for copy output data: {}", copyOutputData); + SPDLOG_DEBUG("Kompute OpAlgoBase constructor with params numTensors: {} copyOutputData: {}, shaderFilePath: {}", tensors.size(), copyOutputData, shaderFilePath); // The dispatch size is set up based on either explicitly provided template // parameters or by default it would take the shape and size of the tensors @@ -942,7 +947,9 @@ OpAlgoBase::OpAlgoBase(std::shared_ptr physicalD this->mY, this->mZ); + this->mShaderFilePath = shaderFilePath; this->mCopyOutputData = copyOutputData; + this->mShaderDataRaw = shaderDataRaw; this->mAlgorithm = std::make_shared(device, commandBuffer); } @@ -1054,24 +1061,32 @@ std::vector OpAlgoBase::fetchSpirvBinaryData() SPDLOG_WARN( "Kompute OpAlgoBase Running shaders directly from spirv file"); - std::ifstream fileStream(this->mOptSpirvBinPath, - std::ios::binary | std::ios::in | std::ios::ate); + if (this->mShaderFilePath.size()) { + std::ifstream fileStream(this->mShaderFilePath, + std::ios::binary | std::ios::in | std::ios::ate); - if (!fileStream.good()) { - throw std::runtime_error("Error reading file: " + this->mOptSpirvBinPath); + if (!fileStream.good()) { + throw std::runtime_error("Error reading file: " + this->mShaderFilePath); + } + + size_t shaderFileSize = fileStream.tellg(); + fileStream.seekg(0, std::ios::beg); + char* shaderDataRaw = new char[shaderFileSize]; + fileStream.read(shaderDataRaw, shaderFileSize); + fileStream.close(); + + SPDLOG_WARN( + "Kompute OpAlgoBase fetched {} bytes", shaderFileSize); + + return std::vector(shaderDataRaw, + shaderDataRaw + shaderFileSize); + } + else if (this->mShaderDataRaw.size()) { + return this->mShaderDataRaw; + } + else { + throw std::runtime_error("Kompute OpAlgoBase Error reached fetchSpirvBinaryData but neither filepath nor data provided"); } - - size_t shaderFileSize = fileStream.tellg(); - fileStream.seekg(0, std::ios::beg); - char* shaderDataRaw = new char[shaderFileSize]; - fileStream.read(shaderDataRaw, shaderFileSize); - fileStream.close(); - - SPDLOG_WARN( - "Kompute OpAlgoBase fetched {} bytes", shaderFileSize); - - return std::vector(shaderDataRaw, - shaderDataRaw + shaderFileSize); } } @@ -1327,12 +1342,12 @@ class OpMult : public OpAlgoBase std::shared_ptr device, std::shared_ptr commandBuffer, std::vector> tensors) - : OpAlgoBase(physicalDevice, device, commandBuffer, tensors, true) + : OpAlgoBase(physicalDevice, device, commandBuffer, tensors, true, "") { SPDLOG_DEBUG("Kompute OpMult constructor with params"); #ifndef RELEASE - this->mOptSpirvBinPath = "shaders/glsl/opmult.comp"; + this->mShaderFilePath = "shaders/glsl/opmult.comp"; #endif } diff --git a/src/include/kompute/operations/OpAlgoBase.hpp b/src/include/kompute/operations/OpAlgoBase.hpp index c63d0536b..fa9eac913 100644 --- a/src/include/kompute/operations/OpAlgoBase.hpp +++ b/src/include/kompute/operations/OpAlgoBase.hpp @@ -50,12 +50,16 @@ class OpAlgoBase : public OpBase * @param device Vulkan logical device for passing to Algorithm * @param commandBuffer Vulkan Command Buffer to record commands into * @param tensors Tensors that are to be used in this operation + * @param copyOutputData Whether to map device data for all output tensors back to their host data vectors + * @param shaderFilePath Optional parameter to specify the shader to load (either in spirv or raw format) */ OpAlgoBase(std::shared_ptr physicalDevice, std::shared_ptr device, std::shared_ptr commandBuffer, std::vector>& tensors, - bool copyOutputData); + bool copyOutputData = false, + std::string shaderFilePath = "", + const std::vector& shaderDataRaw = {}); /** * Default destructor, which is in charge of destroying the algorithm @@ -103,7 +107,8 @@ class OpAlgoBase : public OpBase uint32_t mY; uint32_t mZ; - std::string mOptSpirvBinPath; ///< Optional member variable which can be provided for the OpAlgoBase to find the data automatically and load for processing + std::string mShaderFilePath; ///< Optional member variable which can be provided for the OpAlgoBase to find the data automatically and load for processing + std::vector mShaderDataRaw; ///< Optional member variable which can be provided to contain either the raw shader content or the spirv binary content virtual std::vector fetchSpirvBinaryData(); }; @@ -127,12 +132,12 @@ OpAlgoBase::OpAlgoBase(std::shared_ptr physicalD std::shared_ptr device, std::shared_ptr commandBuffer, std::vector>& tensors, - bool copyOutputData) + bool copyOutputData, + std::string shaderFilePath, + const std::vector& shaderDataRaw) : OpBase(physicalDevice, device, commandBuffer, tensors, false) { - SPDLOG_DEBUG("Kompute OpAlgoBase constructor with params"); - - SPDLOG_DEBUG("Kompute OpAlgoBase configured for copy output data: {}", copyOutputData); + SPDLOG_DEBUG("Kompute OpAlgoBase constructor with params numTensors: {} copyOutputData: {}, shaderFilePath: {}", tensors.size(), copyOutputData, shaderFilePath); // The dispatch size is set up based on either explicitly provided template // parameters or by default it would take the shape and size of the tensors @@ -154,7 +159,9 @@ OpAlgoBase::OpAlgoBase(std::shared_ptr physicalD this->mY, this->mZ); + this->mShaderFilePath = shaderFilePath; this->mCopyOutputData = copyOutputData; + this->mShaderDataRaw = shaderDataRaw; this->mAlgorithm = std::make_shared(device, commandBuffer); } @@ -266,24 +273,32 @@ std::vector OpAlgoBase::fetchSpirvBinaryData() SPDLOG_WARN( "Kompute OpAlgoBase Running shaders directly from spirv file"); - std::ifstream fileStream(this->mOptSpirvBinPath, - std::ios::binary | std::ios::in | std::ios::ate); + if (this->mShaderFilePath.size()) { + std::ifstream fileStream(this->mShaderFilePath, + std::ios::binary | std::ios::in | std::ios::ate); - if (!fileStream.good()) { - throw std::runtime_error("Error reading file: " + this->mOptSpirvBinPath); + if (!fileStream.good()) { + throw std::runtime_error("Error reading file: " + this->mShaderFilePath); + } + + size_t shaderFileSize = fileStream.tellg(); + fileStream.seekg(0, std::ios::beg); + char* shaderDataRaw = new char[shaderFileSize]; + fileStream.read(shaderDataRaw, shaderFileSize); + fileStream.close(); + + SPDLOG_WARN( + "Kompute OpAlgoBase fetched {} bytes", shaderFileSize); + + return std::vector(shaderDataRaw, + shaderDataRaw + shaderFileSize); + } + else if (this->mShaderDataRaw.size()) { + return this->mShaderDataRaw; + } + else { + throw std::runtime_error("Kompute OpAlgoBase Error reached fetchSpirvBinaryData but neither filepath nor data provided"); } - - size_t shaderFileSize = fileStream.tellg(); - fileStream.seekg(0, std::ios::beg); - char* shaderDataRaw = new char[shaderFileSize]; - fileStream.read(shaderDataRaw, shaderFileSize); - fileStream.close(); - - SPDLOG_WARN( - "Kompute OpAlgoBase fetched {} bytes", shaderFileSize); - - return std::vector(shaderDataRaw, - shaderDataRaw + shaderFileSize); } } diff --git a/src/include/kompute/operations/OpMult.hpp b/src/include/kompute/operations/OpMult.hpp index 5eff65ebb..5d51286a7 100644 --- a/src/include/kompute/operations/OpMult.hpp +++ b/src/include/kompute/operations/OpMult.hpp @@ -47,12 +47,12 @@ class OpMult : public OpAlgoBase std::shared_ptr device, std::shared_ptr commandBuffer, std::vector> tensors) - : OpAlgoBase(physicalDevice, device, commandBuffer, tensors, true) + : OpAlgoBase(physicalDevice, device, commandBuffer, tensors, true, "") { SPDLOG_DEBUG("Kompute OpMult constructor with params"); #ifndef RELEASE - this->mOptSpirvBinPath = "shaders/glsl/opmult.comp"; + this->mShaderFilePath = "shaders/glsl/opmult.comp"; #endif } diff --git a/test/TestCustomOpRawShaders.cpp b/test/TestCustomOpRawShaders.cpp new file mode 100644 index 000000000..b4760ff6c --- /dev/null +++ b/test/TestCustomOpRawShaders.cpp @@ -0,0 +1,36 @@ + +#include "catch2/catch.hpp" + +#include "kompute/Kompute.hpp" + +#include + +TEST_CASE("op_custom_simple_raw_shader") { + kp::Manager mgr; + + std::shared_ptr tensorA{ new kp::Tensor({ 3, 4, 5 })}; + std::shared_ptr tensorB{ new kp::Tensor({ 0, 0, 0 })}; + mgr.evalOp({ tensorA, tensorB }); + + std::string shader( + "#version 450\n" + "layout (local_size_x = 1) in;\n" + "layout(set = 0, binding = 0) buffer a { uint pa[]; };\n" + "layout(set = 0, binding = 1) buffer b { uint pb[]; };\n" + "void main() {\n" + " uint index = gl_GlobalInvocationID.x;\n" + " pb[index] = pa[index];\n" + " pa[index] = index;\n" + "}\n" + ); + + mgr.evalOp>( + { tensorA, tensorB }, + "DEFAULT", + true, + "", + std::vector(shader.begin(), shader.end())); + + REQUIRE(tensorA->data() == std::vector{0, 1, 2}); + REQUIRE(tensorB->data() == std::vector{3, 4, 5}); +}