diff --git a/examples/vulkan_ext_printf/CMakeLists.txt b/examples/vulkan_ext_printf/CMakeLists.txt new file mode 100644 index 00000000..d83366a2 --- /dev/null +++ b/examples/vulkan_ext_printf/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 3.20) +project(kompute_vulkan_extensions_printf) + +set(CMAKE_CXX_STANDARD 14) + +# Options +option(KOMPUTE_OPT_GIT_TAG "The tag of the repo to use for the example" v0.9.0) +option(KOMPUTE_OPT_FROM_SOURCE "Whether to build example from source or from git fetch repo" ON) + +if(KOMPUTE_OPT_FROM_SOURCE) + add_subdirectory(../../ ${CMAKE_CURRENT_BINARY_DIR}/kompute_build) +else() + include(FetchContent) + FetchContent_Declare(kompute GIT_REPOSITORY https://github.com/KomputeProject/kompute.git + GIT_TAG ${KOMPUTE_OPT_GIT_TAG}) + FetchContent_MakeAvailable(kompute) + include_directories(${kompute_SOURCE_DIR}/src/include) +endif() + +# Compiling shader +# To add more shaders simply copy the vulkan_compile_shader command and replace it with your new shader +vulkan_compile_shader( + INFILE shader/example_shader.comp + OUTFILE shader/example_shader.hpp + NAMESPACE "shader") + +# Then add it to the library, so you can access it later in your code +add_library(shader INTERFACE "shader/example_shader.hpp") +target_include_directories(shader INTERFACE $) + +# Setting up main example code +add_executable(example_shader_printf src/main.cpp) +target_link_libraries(example_shader_printf PRIVATE shader kompute::kompute) + diff --git a/examples/vulkan_ext_printf/README.md b/examples/vulkan_ext_printf/README.md new file mode 100644 index 00000000..86db7699 --- /dev/null +++ b/examples/vulkan_ext_printf/README.md @@ -0,0 +1,53 @@ +# Kompute Debugging GLSL Shader using DebugPrint + +This folder contains an end to end Kompute Example that implements a GLSL with a debug print statement. +This example is structured such that you will be able to extend it for your project. +It contains a CMake build configuration that can be used in your production applications. + +## Further information +Debugging Vulkan shaders, especially compute shaders, can be very difficult to do even with the aid +of a powerful debugging tool like RenderDoc. Debug Printf is a recent Vulkan feature that allows +developers to debug their shaders by inserting Debug Print statements. This debug print statement operates +quite like the C printf statement, only that it is executed in multiple compute cores at the same time, so it needs some logic to allow semantic usage of the debug statement otherwise you can easily be overwelmed by debug messages. +
+ +This feature is now supported within RenderDoc in a way that allows for per-invocation inspection of values in a shader. +This article describes how to instrument your GLSL or HLSL shaders with Debug Printf and how to +inspect and debug with them in the terminal, using vkconfig, or with environment variables. + +For a full walkthrough of the process please see my article at https://medium.com/@evanokeeffe/using-debug-printf-in-vulkan-kompute-shaders-2aaf30bdb96c + +## Building the example + +You will notice that it's a standalone project, so you can re-use it for your application. +It uses CMake's [`fetch_content`](https://cmake.org/cmake/help/latest/module/FetchContent.html) to consume Kompute as a dependency. +To build you just need to run the CMake command in this folder as follows: + +```bash +git clone https://github.com/KomputeProject/kompute.git +cd kompute/examples/vulkan_ext_printf +mkdir build +cd build +cmake .. +cmake --build . +``` + +## Executing + +From inside the `build/` directory run: + +### Linux + +```bash +./example_shader_printf +``` + +## Pre-requisites + +In order to run this example, you will need the following dependencies: + +* REQUIRED + + The Vulkan SDK must be installed + +For the Vulkan SDK, the simplest way to install it is through [their website](https://vulkan.lunarg.com/sdk/home). You just have to follow the instructions for the relevant platform. + diff --git a/examples/vulkan_ext_printf/shader/example_shader.comp b/examples/vulkan_ext_printf/shader/example_shader.comp new file mode 100644 index 00000000..2d96dce8 --- /dev/null +++ b/examples/vulkan_ext_printf/shader/example_shader.comp @@ -0,0 +1,23 @@ +#version 450 +// To use Debug Printf in GLSL shaders, you need to enable the GL_EXT_debug_printf extension. +// Then add debugPrintfEXT calls at the locations in your shader where you want to print +// messages and/or values +#extension GL_EXT_debug_printf : enable + +// The execution structure +layout (local_size_x = 1) in; + +// The buffers are provided via the tensors +layout(binding = 0) buffer bufA { float a[]; }; +layout(binding = 1) buffer bufB { float b[]; }; +layout(binding = 2) buffer bufOut { float o[]; }; + +void main() { + uint index = gl_GlobalInvocationID.x; + o[index] = a[index] * b[index]; + + // the debug statement operates much the same as printf in C + // do be wary of the size of each line as the default debug message size is + // 1024 bytes + debugPrintfEXT("The result of %f x %f = %f \n", a[index], b[index], o[index]); +} \ No newline at end of file diff --git a/examples/vulkan_ext_printf/src/main.cpp b/examples/vulkan_ext_printf/src/main.cpp new file mode 100644 index 00000000..56c12beb --- /dev/null +++ b/examples/vulkan_ext_printf/src/main.cpp @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include +#include +#include // std::multiplies +#include // std::transform + +#include +#include + +std::vector generate_random_floats(int n, float min_val, float max_val) { + // create std::vector and pre-allocate the vector with n floats + std::vector vectorF = std::vector(n); + // 1. Obtain a random seed from the hardware + std::random_device rd; + // 2. Initialize the generator with the seed + std::mt19937 gen(rd()); + // 3. Define the distribution range [0, n) + std::uniform_real_distribution dis(min_val, max_val); + //fill the vector with randomly distributed floats + for (int i = 0; i < n; i++) {vectorF[i] = dis(gen);} + //return the filled vector + return vectorF; +} + +int main(int argc, char *argv[]) +{ + int device_id = 0; + + if(argc>1){ + device_id = atoi(argv[1]); + }else{ + std::cout<<"Using device 0"< desiredExtensions = std::vector({ + "VK_KHR_shader_non_semantic_info", + }); + const std::vector familyQueueIndices = std::vector({}); + + kp::Manager mgr(device_id, familyQueueIndices, desiredExtensions); + + int vector_length = 10; + + const std::vector A = generate_random_floats(vector_length, 1.0, 10.0); + const std::vector B = generate_random_floats(vector_length, 1.0, 10.0); + const std::vector C = generate_random_floats(vector_length, 0.0, 0.0); + + std::shared_ptr> tensorInA = mgr.tensorT(A); + std::shared_ptr> tensorInB = mgr.tensorT(B); + std::shared_ptr> tensorOut = mgr.tensorT(C); + + const std::vector> params = { tensorInA, + tensorInB, + tensorOut }; + + kp::Workgroup workgroup = { vector_length, 1, 1 }; + + const std::vector shader = std::vector( + shader::EXAMPLE_SHADER_COMP_SPV.begin(), shader::EXAMPLE_SHADER_COMP_SPV.end()); + std::shared_ptr algo = mgr.algorithm(params, shader, workgroup); + + mgr.sequence() + ->record(params) + ->record(algo) + ->record(params) + ->eval(); + + std::cout << "Output: { "; + for (const float& elem : tensorOut->vector()) { std::cout << elem << " ";} + std::cout << "}" << std::endl; +}