|
| 1 | +# Shaders |
| 2 | + |
| 3 | +Shaders work in NDC space: -1 to +1 for X and Y. We set up a triangle's coordinates and output that in the vertex shader save it to `src/glsl/shader.vert`: |
| 4 | + |
| 5 | +```glsl |
| 6 | +#version 450 core |
| 7 | +
|
| 8 | +void main() { |
| 9 | + const vec2 positions[] = { |
| 10 | + vec2(-0.5, -0.5), |
| 11 | + vec2(0.5, -0.5), |
| 12 | + vec2(0.0, 0.5), |
| 13 | + }; |
| 14 | +
|
| 15 | + const vec2 position = positions[gl_VertexIndex]; |
| 16 | +
|
| 17 | + gl_Position = vec4(position, 0.0, 1.0); |
| 18 | +} |
| 19 | +``` |
| 20 | + |
| 21 | +The fragment shader just outputs white for now, in `src/glsl/shader.frag`: |
| 22 | + |
| 23 | +```glsl |
| 24 | +#version 450 core |
| 25 | +
|
| 26 | +layout (location = 0) out vec4 out_color; |
| 27 | +
|
| 28 | +void main() { |
| 29 | + out_color = vec4(1.0); |
| 30 | +} |
| 31 | +``` |
| 32 | + |
| 33 | +Compile both shaders into `assets/`: |
| 34 | + |
| 35 | +``` |
| 36 | +glslc src/glsl/shader.vert -o assets/shader.vert |
| 37 | +glslc src/glsl/shader.frag -o assets/shader.frag |
| 38 | +``` |
| 39 | + |
| 40 | +## Shader Modules |
| 41 | + |
| 42 | +SPIR-V modules are binary files with a stride/alignment of 4 bytes. The Vulkan API accepts a span of `std::uint32_t`s, so we need to load it into such a buffer (and _not_ `std::vector<std::byte>` or other 1-byte equivalents). |
| 43 | + |
| 44 | +Add a new `class ShaderLoader`: |
| 45 | + |
| 46 | +```cpp |
| 47 | +class ShaderLoader { |
| 48 | + public: |
| 49 | + explicit ShaderLoader(vk::Device const device) : m_device(device) {} |
| 50 | + |
| 51 | + [[nodiscard]] auto load(fs::path const& path) -> vk::UniqueShaderModule; |
| 52 | + |
| 53 | + private: |
| 54 | + vk::Device m_device{}; |
| 55 | + std::vector<std::uint32_t> m_code{}; |
| 56 | +}; |
| 57 | +``` |
| 58 | +
|
| 59 | +Implement `load()`: |
| 60 | +
|
| 61 | +```cpp |
| 62 | +auto ShaderLoader::load(fs::path const& path) -> vk::UniqueShaderModule { |
| 63 | + // open the file at the end, to get the total size. |
| 64 | + auto file = std::ifstream{path, std::ios::binary | std::ios::ate}; |
| 65 | + if (!file.is_open()) { |
| 66 | + std::println(stderr, "Failed to open file: '{}'", |
| 67 | + path.generic_string()); |
| 68 | + return {}; |
| 69 | + } |
| 70 | +
|
| 71 | + auto const size = file.tellg(); |
| 72 | + auto const usize = static_cast<std::uint64_t>(size); |
| 73 | + // file data must be uint32 aligned. |
| 74 | + if (usize % sizeof(std::uint32_t) != 0) { |
| 75 | + std::println(stderr, "Invalid SPIR-V size: {}", usize); |
| 76 | + return {}; |
| 77 | + } |
| 78 | +
|
| 79 | + // seek to the beginning before reading. |
| 80 | + file.seekg({}, std::ios::beg); |
| 81 | + m_code.resize(usize / sizeof(std::uint32_t)); |
| 82 | + void* data = m_code.data(); |
| 83 | + file.read(static_cast<char*>(data), size); |
| 84 | +
|
| 85 | + auto shader_module_ci = vk::ShaderModuleCreateInfo{}; |
| 86 | + shader_module_ci.setCode(m_code); |
| 87 | + return m_device.createShaderModuleUnique(shader_module_ci); |
| 88 | +} |
| 89 | +``` |
| 90 | + |
| 91 | +Add new members to `App`: |
| 92 | + |
| 93 | +```cpp |
| 94 | +void create_pipeline(); |
| 95 | + |
| 96 | +[[nodiscard]] auto asset_path(std::string_view uri) const -> fs::path; |
| 97 | +``` |
| 98 | +
|
| 99 | +Implement and call `create_pipeline()` before starting the main loop: |
| 100 | +
|
| 101 | +```cpp |
| 102 | +auto App::asset_path(std::string_view const uri) const -> fs::path { |
| 103 | + return m_assets_dir / uri; |
| 104 | +} |
| 105 | +
|
| 106 | +void App::create_pipeline() { |
| 107 | + auto shader_loader = ShaderLoader{*m_device}; |
| 108 | + // we only need shader modules to create the pipeline, thus no need to store |
| 109 | + // them as members. |
| 110 | + auto const vertex = shader_loader.load(asset_path("shader.vert")); |
| 111 | + auto const fragment = shader_loader.load(asset_path("shader.frag")); |
| 112 | + if (!vertex || !fragment) { |
| 113 | + throw std::runtime_error{"Failed to load Shaders"}; |
| 114 | + } |
| 115 | + std::println("[lvk] Shaders loaded"); |
| 116 | +
|
| 117 | + // TODO |
| 118 | +} |
| 119 | +``` |
0 commit comments