// SPDX-License-Identifier: Apache-2.0 #include "gtest/gtest.h" #include "kompute/Kompute.hpp" #include "kompute/logger/Logger.hpp" #include "shaders/Utils.hpp" TEST(TestMultipleAlgoExecutions, TestEndToEndFunctionality) { kp::Manager mgr; // Default tensor constructor simplifies creation of float values auto tensorInA = mgr.tensor({ 2., 2., 2. }); auto tensorInB = mgr.tensor({ 1., 2., 3. }); // Explicit type constructor supports int, in32, double, float and int auto tensorOutA = mgr.tensorT({ 0, 0, 0 }); auto tensorOutB = mgr.tensorT({ 0, 0, 0 }); std::string shader = (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_a { float in_a[]; }; layout(set = 0, binding = 1) buffer buf_in_b { float in_b[]; }; layout(set = 0, binding = 2) buffer buf_out_a { uint out_a[]; }; layout(set = 0, binding = 3) buffer buf_out_b { uint out_b[]; }; // Kompute supports push constants updated on dispatch layout(push_constant) uniform PushConstants { float val; } push_const; // Kompute also supports spec constants on initalization layout(constant_id = 0) const float const_one = 0; void main() { uint index = gl_GlobalInvocationID.x; out_a[index] += uint( in_a[index] * in_b[index] ); out_b[index] += uint( const_one * push_const.val ); } )"); std::vector> params = { tensorInA, tensorInB, tensorOutA, tensorOutB }; kp::Workgroup workgroup({ 3, 1, 1 }); std::vector specConsts({ 2 }); std::vector pushConstsA({ 2.0 }); std::vector pushConstsB({ 3.0 }); auto algorithm = mgr.algorithm( params, compileSource(shader), workgroup, specConsts, pushConstsA); // 3. Run operation with string shader synchronously mgr.sequence() ->record(params) ->record(algorithm) ->eval() ->record(algorithm, pushConstsB) ->eval(); auto sq = mgr.sequence(); sq->evalAsync(params); sq->evalAwait(); EXPECT_EQ(tensorOutA->vector(), std::vector({ 4, 8, 12 })); EXPECT_EQ(tensorOutB->vector(), std::vector({ 10, 10, 10 })); } TEST(TestMultipleAlgoExecutions, SingleSequenceRecord) { kp::Manager mgr; std::shared_ptr> tensorA = mgr.tensor({ 0, 0, 0 }); std::string shader(R"( #version 450 layout (local_size_x = 1) in; layout(set = 0, binding = 0) buffer a { float pa[]; }; void main() { uint index = gl_GlobalInvocationID.x; pa[index] = pa[index] + 1; })"); std::vector spirv = compileSource(shader); { // A sharedMemoryBarrier is required as the shader is not thread-safe:w std::shared_ptr shaderBarrier{ new kp::OpMemoryBarrier({ tensorA }, vk::AccessFlagBits::eTransferRead, vk::AccessFlagBits::eShaderWrite, vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eComputeShader) }; mgr.sequence() ->record({ tensorA }) ->record(mgr.algorithm({ tensorA }, spirv)) ->record(shaderBarrier) ->record(mgr.algorithm({ tensorA }, spirv)) ->record(shaderBarrier) ->record(mgr.algorithm({ tensorA }, spirv)) ->record({ tensorA }) ->eval(); } EXPECT_EQ(tensorA->vector(), std::vector({ 3, 3, 3 })); } TEST(TestMultipleAlgoExecutions, MultipleCmdBufRecords) { kp::Manager mgr; std::shared_ptr> tensorA = mgr.tensor({ 0, 0, 0 }); std::string shader(R"( #version 450 layout (local_size_x = 1) in; layout(set = 0, binding = 0) buffer a { float pa[]; }; void main() { uint index = gl_GlobalInvocationID.x; pa[index] = pa[index] + 1; })"); std::vector spirv = compileSource(shader); std::shared_ptr algorithm = mgr.algorithm({ tensorA }, spirv); std::shared_ptr sq = mgr.sequence(); mgr.sequence()->record({ tensorA })->eval(); mgr.sequence()->record(algorithm)->eval(); mgr.sequence()->record(algorithm)->eval(); mgr.sequence()->record(algorithm)->eval(); mgr.sequence()->record({ tensorA })->eval(); EXPECT_EQ(tensorA->vector(), std::vector({ 3, 3, 3 })); } TEST(TestMultipleAlgoExecutions, MultipleSequences) { kp::Manager mgr; std::shared_ptr> tensorA = mgr.tensor({ 0, 0, 0 }); std::string shader(R"( #version 450 layout (local_size_x = 1) in; layout(set = 0, binding = 0) buffer a { float pa[]; }; void main() { uint index = gl_GlobalInvocationID.x; pa[index] = pa[index] + 1; })"); std::vector spirv = compileSource(shader); std::shared_ptr algorithm = mgr.algorithm({ tensorA }, spirv); std::shared_ptr sq = mgr.sequence(); sq->record({ tensorA })->eval(); sq->record(algorithm)->eval(); sq->record(algorithm)->eval(); sq->record(algorithm)->eval(); sq->record({ tensorA })->eval(); EXPECT_EQ(tensorA->vector(), std::vector({ 3, 3, 3 })); } TEST(TestMultipleAlgoExecutions, SingleRecordMultipleEval) { kp::Manager mgr; std::shared_ptr> tensorA = mgr.tensor({ 0, 0, 0 }); std::string shader(R"( #version 450 layout (local_size_x = 1) in; layout(set = 0, binding = 0) buffer a { float pa[]; }; void main() { uint index = gl_GlobalInvocationID.x; pa[index] = pa[index] + 1; })"); std::vector spirv = compileSource(shader); std::shared_ptr algorithm = mgr.algorithm({ tensorA }, spirv); std::shared_ptr sq = mgr.sequence(); sq->record({ tensorA })->eval(); sq->record(algorithm)->eval()->eval()->eval(); sq->record({ tensorA })->eval(); EXPECT_EQ(tensorA->vector(), std::vector({ 3, 3, 3 })); } TEST(TestMultipleAlgoExecutions, TestAlgorithmUtilFunctions) { kp::Manager mgr; // Default tensor constructor simplifies creation of float values auto tensorInA = mgr.tensor({ 2., 2., 2. }); auto tensorInB = mgr.tensor({ 1., 2., 3. }); // Explicit type constructor supports int, in32, double, float and int auto tensorOutA = mgr.tensorT({ 0, 0, 0 }); auto tensorOutB = mgr.tensorT({ 0, 0, 0 }); std::string shader = (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_a { float in_a[]; }; layout(set = 0, binding = 1) buffer buf_in_b { float in_b[]; }; layout(set = 0, binding = 2) buffer buf_out_a { uint out_a[]; }; layout(set = 0, binding = 3) buffer buf_out_b { uint out_b[]; }; // Kompute supports push constants updated on dispatch layout(push_constant) uniform PushConstants { float val; } push_const; // Kompute also supports spec constants on initalization layout(constant_id = 0) const float const_one = 0; void main() { uint index = gl_GlobalInvocationID.x; out_a[index] += uint( in_a[index] * in_b[index] ); out_b[index] += uint( const_one * push_const.val ); } )"); std::vector> params = { tensorInA, tensorInB, tensorOutA, tensorOutB }; kp::Workgroup workgroup({ 3, 1, 1 }); std::vector specConsts({ 2 }); std::vector pushConsts({ 2.0 }); auto algorithm = mgr.algorithm( params, compileSource(shader), workgroup, specConsts, pushConsts); EXPECT_EQ(algorithm->getWorkgroup(), workgroup); EXPECT_EQ(algorithm->getPushConstants(), pushConsts); EXPECT_EQ(algorithm->getSpecializationConstants(), specConsts); }