Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

Commit bf36e60

Browse files
committed
Merge branch 'main' into tymii/17-inconsistent-file-naming
2 parents aaa3bc8 + 66799bf commit bf36e60

20 files changed

+348
-122
lines changed

App/Src/Main.cpp

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -50,20 +50,21 @@ namespace
5050
const auto& renderDevice = engine.RenderDevice();
5151
if (!shader.Load(renderDevice.get_device(), vertexSpirV, fragmentSpirV)) { throw std::runtime_error{"Failed to load shaders"}; }
5252

53-
const auto pipelineLayout = renderDevice.get_device().createPipelineLayoutUnique({});
53+
constexpr auto vertices = std::array{
54+
Tkge::Graphics::Vertex{.position = {-0.5f, -0.5f}, .colour = kvf::red_v.to_vec4()},
55+
Tkge::Graphics::Vertex{.position = {0.5f, -0.5f}, .colour = kvf::green_v.to_vec4()},
56+
Tkge::Graphics::Vertex{.position = {0.5f, 0.5f}, .colour = kvf::blue_v.to_vec4()},
57+
Tkge::Graphics::Vertex{.position = {-0.5f, 0.5f}, .colour = kvf::yellow_v.to_vec4()},
58+
};
5459

55-
const auto pipelineState = kvf::PipelineState{
56-
.vertex_bindings = {},
57-
.vertex_attributes = {},
58-
.vertex_shader = shader.VertexModule(),
59-
.fragment_shader = shader.FragmentModule(),
60+
constexpr auto indices = std::array{
61+
0u, 1u, 2u, 2u, 3u, 0u,
6062
};
61-
const auto pipelineFormat = kvf::PipelineFormat{
62-
.samples = engine.FramebufferSamples(),
63-
.color = engine.FramebufferFormat(),
63+
64+
const auto primitive = Tkge::Graphics::Primitive{
65+
.vertices = vertices,
66+
.indices = indices,
6467
};
65-
const auto pipeline = renderDevice.create_pipeline(*pipelineLayout, pipelineState, pipelineFormat);
66-
if (!pipeline) { throw std::runtime_error{"Failed to create graphics pipeline"}; }
6768

6869
auto wireframe = false;
6970
auto lineWidth = 3.0f;
@@ -84,7 +85,7 @@ namespace
8485
renderer.BindShader(shader);
8586
renderer.SetLineWidth(lineWidth);
8687
renderer.SetWireframe(wireframe);
87-
renderer.Draw(3);
88+
renderer.Draw(primitive);
8889
}
8990

9091
engine.Present();

Assets/shaders/default.frag

452 Bytes
Binary file not shown.

Assets/shaders/default.vert

1.07 KB
Binary file not shown.

Assets/shaders/triangle.vert

-1.51 KB
Binary file not shown.

Lib/Include/Tkge/Engine.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ namespace Tkge
4545
kvf::RenderDevice _renderDevice;
4646
kvf::RenderPass _renderPass;
4747

48-
Graphics::ResourcePool _resourcePool;
48+
std::unique_ptr<Graphics::IResourcePool> _resourcePool{};
4949

5050
vk::CommandBuffer _cmd{};
5151
AssetLoader _assetLoader;
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#pragma once
2+
#include <vulkan/vulkan.hpp>
3+
4+
namespace Tkge::Graphics
5+
{
6+
/// \brief Description of a unique Pipeline's fixed state.
7+
struct PipelineFixedState
8+
{
9+
/// \brief Colour image format of target Render Pass.
10+
vk::Format colourFormat{};
11+
12+
vk::PrimitiveTopology topology{vk::PrimitiveTopology::eTriangleList};
13+
vk::PolygonMode polygonMode{vk::PolygonMode::eFill};
14+
};
15+
} // namespace Tkge::Graphics
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#pragma once
2+
#include <Tkge/Graphics/Vertex.hpp>
3+
#include <span>
4+
5+
namespace Tkge::Graphics
6+
{
7+
struct Primitive
8+
{
9+
std::span<const Vertex> vertices{};
10+
std::span<const std::uint32_t> indices{};
11+
12+
vk::PrimitiveTopology topology{vk::PrimitiveTopology::eTriangleList};
13+
};
14+
} // namespace Tkge::Graphics

Lib/Include/Tkge/Graphics/Renderer.hpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#pragma once
2+
#include <Tkge/Graphics/Primitive.hpp>
23
#include <Tkge/Graphics/ResourcePool.hpp>
34
#include <kvf/render_pass.hpp>
45

@@ -14,7 +15,7 @@ namespace Tkge::Graphics
1415

1516
Renderer() = default;
1617

17-
explicit Renderer(kvf::RenderPass* renderPass, ResourcePool* resourcePool, vk::CommandBuffer commandBuffer, glm::ivec2 framebufferSize);
18+
explicit Renderer(kvf::RenderPass* renderPass, IResourcePool* resourcePool, vk::CommandBuffer commandBuffer, glm::ivec2 framebufferSize);
1819
~Renderer() { EndRender(); }
1920

2021
[[nodiscard]] bool IsRendering() const { return _renderPass != nullptr; }
@@ -24,14 +25,15 @@ namespace Tkge::Graphics
2425
void SetLineWidth(float width);
2526
void SetWireframe(bool wireframe);
2627

27-
// temporary, until we have vertices, primitives, etc
28-
void Draw(std::uint32_t vertices);
28+
void Draw(const Primitive& primitive);
2929

3030
explicit operator bool() const { return IsRendering(); }
3131

3232
private:
33+
void BindVboAndDraw(const Primitive& primitive) const;
34+
3335
kvf::RenderPass* _renderPass{};
34-
ResourcePool* _resourcePool{};
36+
IResourcePool* _resourcePool{};
3537

3638
const Shader* _shader{};
3739
vk::Pipeline _pipeline{};
Lines changed: 13 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,24 @@
11
#pragma once
2+
#include <Tkge/Graphics/PipelineFixedState.hpp>
23
#include <Tkge/Graphics/Shader.hpp>
3-
#include <kvf/render_device.hpp>
4-
#include <unordered_map>
4+
#include <kvf/vma.hpp>
55

66
namespace Tkge::Graphics
77
{
8-
class PipelinePool
9-
{
10-
public:
11-
struct Params
12-
{
13-
vk::Format colourFormat{};
14-
15-
vk::PrimitiveTopology topology{vk::PrimitiveTopology::eTriangleList};
16-
vk::PolygonMode polygonMode{vk::PolygonMode::eFill};
17-
};
18-
19-
explicit PipelinePool(gsl::not_null<const kvf::RenderDevice*> renderDevice, vk::SampleCountFlagBits framebufferSamples);
20-
21-
[[nodiscard]] vk::PipelineLayout PipelineLayout() const { return *_pipelineLayout; }
8+
using Buffer = kvf::vma::Buffer;
229

23-
[[nodiscard]] vk::Pipeline GetPipeline(const Shader& shader, const Params& params);
24-
25-
private:
26-
gsl::not_null<const kvf::RenderDevice*> _renderDevice;
27-
vk::SampleCountFlagBits _framebufferSamples;
28-
29-
vk::UniquePipelineLayout _pipelineLayout{};
30-
std::unordered_map<std::size_t, vk::UniquePipeline> _pipelines{};
31-
};
32-
33-
class ResourcePool
10+
class IResourcePool : public klib::Polymorphic
3411
{
3512
public:
36-
explicit ResourcePool(gsl::not_null<const kvf::RenderDevice*> renderDevice, vk::SampleCountFlagBits framebufferSamples)
37-
: pipelinePool(renderDevice, framebufferSamples)
38-
{
39-
}
13+
[[nodiscard]] virtual vk::PipelineLayout PipelineLayout() const = 0;
14+
15+
/// \brief Get the Pipeline identified by the input parameters.
16+
/// \param shader Shader that will be used in draw calls (dynamic Pipeline state).
17+
/// \param state Fixed Pipeline state.
18+
/// \returns Existing Pipeline if already cached, otherwise a newly created one (unless creation fails).
19+
[[nodiscard]] virtual vk::Pipeline GetPipeline(const Shader& shader, const PipelineFixedState& state) = 0;
4020

41-
PipelinePool pipelinePool;
21+
/// \brief Allocate a Buffer for given usage and of given size.
22+
[[nodiscard]] virtual Buffer& AllocateBuffer(vk::BufferUsageFlags usage, vk::DeviceSize size) = 0;
4223
};
4324
} // namespace Tkge::Graphics

Lib/Include/Tkge/Graphics/Vertex.hpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#pragma once
2+
#include <glm/vec2.hpp>
3+
#include <glm/vec4.hpp>
4+
5+
namespace Tkge::Graphics
6+
{
7+
struct Vertex
8+
{
9+
glm::vec2 position{};
10+
glm::vec4 colour{1.0f};
11+
glm::vec2 uv{};
12+
};
13+
} // namespace Tkge::Graphics
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#pragma once
2+
#include <Tkge/Graphics/Vertex.hpp>
3+
#include <cstdint>
4+
#include <span>
5+
#include <vector>
6+
7+
namespace Tkge::Graphics
8+
{
9+
struct VertexArray
10+
{
11+
std::vector<Vertex> vertices{};
12+
std::vector<std::uint32_t> indices{};
13+
14+
void Reserve(std::size_t vertexCount, std::size_t indexCount);
15+
void Clear();
16+
auto Append(std::span<const Vertex> vertices, std::span<const std::uint32_t> indices) -> VertexArray&;
17+
};
18+
} // namespace Tkge::Graphics

Lib/Src/Detail/BufferPool.hpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#pragma once
2+
#include <kvf/render_device.hpp>
3+
#include <kvf/vma.hpp>
4+
#include <vulkan/vulkan_hash.hpp>
5+
6+
namespace Tkge::Detail
7+
{
8+
/// \brief Cached storage for Vulkan Host Buffers.
9+
class BufferPool
10+
{
11+
public:
12+
explicit BufferPool(gsl::not_null<kvf::RenderDevice*> renderDevice) : _renderDevice(renderDevice) {}
13+
14+
// Allocate a Buffer for given usage and of given size.
15+
[[nodiscard]] kvf::vma::Buffer& Allocate(vk::BufferUsageFlags usage, vk::DeviceSize size)
16+
{
17+
const auto frameIndex = _renderDevice->get_frame_index();
18+
auto& poolMap = _poolMaps.at(std::size_t(frameIndex));
19+
auto& pool = poolMap[std::hash<vk::BufferUsageFlags>{}(usage)];
20+
if (pool.next < pool.buffers.size())
21+
{
22+
auto& ret = pool.buffers.at(pool.next++);
23+
ret.resize(size);
24+
return ret;
25+
}
26+
const auto createInfo = kvf::vma::BufferCreateInfo{
27+
.usage = usage,
28+
.type = kvf::vma::BufferType::Host,
29+
};
30+
pool.next = pool.buffers.size() + 1;
31+
return pool.buffers.emplace_back(_renderDevice, createInfo, size);
32+
}
33+
34+
// Make all buffers for the current frame available for use.
35+
void NextFrame()
36+
{
37+
// GPU has finished rendering the current frame, these resources can now be reused.
38+
// (Other frames may still be being rendered, hence the multiple buffering.)
39+
const auto frameIndex = _renderDevice->get_frame_index();
40+
auto& poolMap = _poolMaps.at(std::size_t(frameIndex));
41+
for (auto& [_, pool] : poolMap) { pool.next = 0; }
42+
}
43+
44+
private:
45+
struct Pool
46+
{
47+
std::vector<kvf::vma::Buffer> buffers{}; // buffer pool for a specific usage
48+
std::size_t next{}; // index of next available buffer
49+
};
50+
51+
using PoolMap = std::unordered_map<std::size_t, Pool>; // map of hash(usage) => Pool
52+
53+
gsl::not_null<kvf::RenderDevice*> _renderDevice;
54+
55+
kvf::Buffered<PoolMap> _poolMaps{}; // double/triple/etc buffered pools
56+
};
57+
} // namespace Tkge::Detail

Lib/Src/Detail/PipelinePool.hpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#pragma once
2+
#include <Tkge/Graphics/PipelineFixedState.hpp>
3+
#include <Tkge/Graphics/Shader.hpp>
4+
#include <Tkge/Graphics/Vertex.hpp>
5+
#include <klib/hash_combine.hpp>
6+
#include <kvf/render_device.hpp>
7+
#include <unordered_map>
8+
9+
namespace Tkge::Detail
10+
{
11+
/// \brief Cached storage for Vulkan Graphics Pipelines.
12+
class PipelinePool
13+
{
14+
public:
15+
using FixedState = Graphics::PipelineFixedState;
16+
17+
/// \param renderDevice Pointer to valid RenderDevice.
18+
/// \param framebufferSamples Sample count of target Render Pass' colour attachment.
19+
explicit PipelinePool(gsl::not_null<const kvf::RenderDevice*> renderDevice, vk::SampleCountFlagBits framebufferSamples)
20+
: _renderDevice(renderDevice), _framebufferSamples(framebufferSamples)
21+
{
22+
// TODO: descriptor set layouts
23+
_pipelineLayout = renderDevice->get_device().createPipelineLayoutUnique({});
24+
}
25+
26+
[[nodiscard]] vk::PipelineLayout PipelineLayout() const { return *_pipelineLayout; }
27+
28+
/// \brief Get the Pipeline identified by the input parameters.
29+
/// \param shader Shader that will be used in draw calls (dynamic Pipeline state).
30+
/// \param state Fixed Pipeline state.
31+
/// \returns Existing Pipeline if already cached, otherwise a newly created one (unless creation fails).
32+
[[nodiscard]] vk::Pipeline GetPipeline(const Graphics::Shader& shader, const FixedState& state)
33+
{
34+
using Graphics::Vertex;
35+
36+
// A single Vertex Buffer is bound during draw (index 0), containing vertices.
37+
static constexpr auto VertexBindings = std::array{
38+
vk::VertexInputBindingDescription{0, sizeof(Vertex)},
39+
};
40+
41+
// Attributes for Vertex Buffer at index 0: list of interleaved vertices (span<Vertex>).
42+
static constexpr auto VertexAttributes = std::array{
43+
vk::VertexInputAttributeDescription{0, 0, vk::Format::eR32G32Sfloat, offsetof(Vertex, position)},
44+
vk::VertexInputAttributeDescription{1, 0, vk::Format::eR32G32B32A32Sfloat, offsetof(Vertex, colour)},
45+
vk::VertexInputAttributeDescription{2, 0, vk::Format::eR32G32Sfloat, offsetof(Vertex, uv)},
46+
};
47+
48+
const auto key = klib::make_combined_hash(shader.GetHash(), state.colourFormat, state.polygonMode, state.topology);
49+
auto it = _pipelines.find(key);
50+
if (it != _pipelines.end()) { return *it->second; }
51+
52+
const auto pipelineState = kvf::PipelineState{
53+
.vertex_bindings = VertexBindings,
54+
.vertex_attributes = VertexAttributes,
55+
.vertex_shader = shader.VertexModule(),
56+
.fragment_shader = shader.FragmentModule(),
57+
.topology = state.topology,
58+
.polygon_mode = state.polygonMode,
59+
};
60+
const auto pipelineFormat = kvf::PipelineFormat{
61+
.samples = _framebufferSamples,
62+
.color = state.colourFormat,
63+
};
64+
auto ret = _renderDevice->create_pipeline(*_pipelineLayout, pipelineState, pipelineFormat);
65+
if (!ret) { return {}; }
66+
67+
it = _pipelines.insert({key, std::move(ret)}).first;
68+
return *it->second;
69+
}
70+
71+
private:
72+
gsl::not_null<const kvf::RenderDevice*> _renderDevice;
73+
vk::SampleCountFlagBits _framebufferSamples;
74+
75+
vk::UniquePipelineLayout _pipelineLayout{};
76+
std::unordered_map<std::size_t, vk::UniquePipeline> _pipelines{};
77+
};
78+
} // namespace Tkge::Detail

0 commit comments

Comments
 (0)