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

Commit 3dbd1d2

Browse files
authored
Add graphics::Renderer (WIP) (#8)
1 parent f943677 commit 3dbd1d2

File tree

8 files changed

+216
-20
lines changed

8 files changed

+216
-20
lines changed

app/src/main.cpp

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,16 +65,29 @@ namespace
6565
const auto pipeline = renderDevice.create_pipeline(*pipelineLayout, pipelineState, pipelineFormat);
6666
if (!pipeline) { throw std::runtime_error{"Failed to create graphics pipeline"}; }
6767

68+
auto wireframe = false;
69+
auto lineWidth = 3.0f;
70+
6871
while (engine.IsRunning())
6972
{
70-
const auto commandBuffer = engine.NextFrame();
73+
engine.NextFrame();
74+
75+
if (ImGui::Begin("Misc"))
76+
{
77+
ImGui::Checkbox("wireframe", &wireframe);
78+
ImGui::DragFloat("line width", &lineWidth, 1.0f, 1.0f, 100.0f);
79+
}
80+
ImGui::End();
7181

72-
ImGui::ShowDemoWindow();
82+
if (auto renderer = engine.BeginRender())
83+
{
84+
renderer.BindShader(shader);
85+
renderer.SetLineWidth(lineWidth);
86+
renderer.SetWireframe(wireframe);
87+
renderer.Draw(3);
88+
}
7389

74-
engine.BeginRender();
75-
engine.RenderPass().bind_pipeline(*pipeline);
76-
commandBuffer.draw(3, 1, 0, 0);
77-
engine.EndRender();
90+
engine.Present();
7891
}
7992

8093
renderDevice.get_device().waitIdle();

ext/src.zip

34 Bytes
Binary file not shown.

lib/include/tkge/engine.hpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
#include <kvf/render_device.hpp>
66
#include <kvf/render_pass.hpp>
77
#include <kvf/window.hpp>
8-
#include "assetLoader.hpp"
8+
#include <tkge/assetLoader.hpp>
9+
#include <tkge/graphics/renderer.hpp>
910

1011
namespace tkge
1112
{
@@ -24,17 +25,15 @@ namespace tkge
2425
explicit Engine(const WindowSurface& surface = {}, vk::SampleCountFlagBits aa = AntiAliasing);
2526

2627
[[nodiscard]] const kvf::RenderDevice& RenderDevice() const { return _renderDevice; }
27-
[[nodiscard]] const kvf::RenderPass& RenderPass() const { return _renderPass; }
2828

2929
[[nodiscard]] glm::ivec2 FramebufferSize() const;
3030
[[nodiscard]] auto FramebufferFormat() const -> vk::Format { return _renderPass.get_color_format(); }
3131
[[nodiscard]] auto FramebufferSamples() const -> vk::SampleCountFlagBits { return _renderPass.get_samples(); }
3232

3333
[[nodiscard]] bool IsRunning() const;
3434
vk::CommandBuffer NextFrame();
35-
// TODO: return Renderer
36-
void BeginRender(kvf::Color clear = kvf::black_v);
37-
void EndRender();
35+
[[nodiscard]] graphics::Renderer BeginRender(kvf::Color clear = kvf::black_v);
36+
void Present();
3837

3938
[[nodiscard]] AssetLoader& GetAssetLoader() noexcept { return this->_assetLoader; }
4039
[[nodiscard]] const AssetLoader& GetAssetLoader() const noexcept { return this->_assetLoader; }
@@ -46,6 +45,8 @@ namespace tkge
4645
kvf::RenderDevice _renderDevice;
4746
kvf::RenderPass _renderPass;
4847

48+
graphics::ResourcePool _resourcePool;
49+
4950
vk::CommandBuffer _cmd{};
5051
AssetLoader _assetLoader;
5152
};
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#pragma once
2+
#include <kvf/render_pass.hpp>
3+
#include <tkge/graphics/resource_pool.hpp>
4+
5+
namespace tkge::graphics
6+
{
7+
class Renderer
8+
{
9+
public:
10+
Renderer(Renderer&&) = delete;
11+
Renderer(const Renderer&) = delete;
12+
Renderer& operator=(const Renderer&) = delete;
13+
Renderer& operator=(Renderer&&) = delete;
14+
15+
Renderer() = default;
16+
17+
explicit Renderer(kvf::RenderPass* renderPass, ResourcePool* resourcePool, vk::CommandBuffer commandBuffer, glm::ivec2 framebufferSize);
18+
~Renderer() { EndRender(); }
19+
20+
[[nodiscard]] bool IsRendering() const { return _renderPass != nullptr; }
21+
void EndRender();
22+
23+
bool BindShader(const Shader& shader);
24+
void SetLineWidth(float width);
25+
void SetWireframe(bool wireframe);
26+
27+
// temporary, until we have vertices, primitives, etc
28+
void Draw(std::uint32_t vertices);
29+
30+
explicit operator bool() const { return IsRendering(); }
31+
32+
private:
33+
kvf::RenderPass* _renderPass{};
34+
ResourcePool* _resourcePool{};
35+
36+
const Shader* _shader{};
37+
vk::Pipeline _pipeline{};
38+
vk::PolygonMode _polygonMode{vk::PolygonMode::eFill};
39+
float _lineWidth{1.0f};
40+
};
41+
} // namespace tkge::graphics
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#pragma once
2+
#include <kvf/render_device.hpp>
3+
#include <tkge/graphics/shader.hpp>
4+
#include <unordered_map>
5+
6+
namespace tkge::graphics
7+
{
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; }
22+
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
34+
{
35+
public:
36+
explicit ResourcePool(gsl::not_null<const kvf::RenderDevice*> renderDevice, vk::SampleCountFlagBits framebufferSamples)
37+
: pipelinePool(renderDevice, framebufferSamples)
38+
{
39+
}
40+
41+
PipelinePool pipelinePool;
42+
};
43+
} // namespace tkge::graphics

lib/src/engine.cpp

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
11
#include <klib/assert.hpp>
2+
#include <kvf/is_positive.hpp>
23
#include <kvf/util.hpp>
3-
#include <tkge/Assets/TextAsset.hpp>
44
#include <tkge/engine.hpp>
55
#include <print>
66

77
namespace tkge
88
{
99
Engine::Engine(const WindowSurface& surface, const vk::SampleCountFlagBits aa)
10-
: _window(CreateWindow(surface)), _renderDevice(_window.get()), _renderPass(&_renderDevice, aa)
10+
: _window(CreateWindow(surface)), _renderDevice(_window.get()), _renderPass(&_renderDevice, aa), _resourcePool(&_renderDevice, aa)
1111
{
1212
_renderPass.set_color_target();
13-
// TEST
14-
const auto myTextDocument = this->GetAssetLoader().LoadAsset<tkge::Assets::TextAsset>("hello.txt");
15-
std::println("Document content = '{}'", myTextDocument->ReadAllText());
1613
}
1714

1815
glm::ivec2 Engine::FramebufferSize() const { return kvf::util::to_glm_vec<int>(_renderDevice.get_framebuffer_extent()); }
@@ -35,15 +32,20 @@ namespace tkge
3532
return ret;
3633
}
3734

38-
void Engine::BeginRender(const kvf::Color clear)
35+
graphics::Renderer Engine::BeginRender(const kvf::Color clear)
3936
{
37+
if (!_cmd) { return {}; }
38+
39+
const auto framebufferSize = FramebufferSize();
40+
if (!kvf::is_positive(framebufferSize)) { return {}; }
41+
4042
_renderPass.clear_color = clear.to_linear();
41-
_renderPass.begin_render(_cmd, _renderDevice.get_framebuffer_extent());
43+
return graphics::Renderer{&_renderPass, &_resourcePool, _cmd, framebufferSize};
4244
}
4345

44-
void Engine::EndRender()
46+
void Engine::Present()
4547
{
46-
_renderPass.end_render();
48+
if (_renderPass.get_command_buffer()) { _renderPass.end_render(); }
4749
_renderDevice.render(_renderPass.render_target());
4850
}
4951
} // namespace tkge

lib/src/graphics/renderer.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#include <kvf/util.hpp>
2+
#include <tkge/graphics/renderer.hpp>
3+
#include <algorithm>
4+
5+
namespace tkge::graphics
6+
{
7+
Renderer::Renderer(kvf::RenderPass* renderPass, ResourcePool* resourcePool, const vk::CommandBuffer commandBuffer, const glm::ivec2 framebufferSize)
8+
: _renderPass(renderPass), _resourcePool(resourcePool)
9+
{
10+
_renderPass->begin_render(commandBuffer, kvf::util::to_vk_extent(framebufferSize));
11+
}
12+
13+
void Renderer::EndRender()
14+
{
15+
if (_renderPass == nullptr) { return; }
16+
_renderPass->end_render();
17+
_renderPass = nullptr;
18+
}
19+
20+
bool Renderer::BindShader(const Shader& shader)
21+
{
22+
if (!IsRendering() || !shader.IsLoaded()) { return false; }
23+
_shader = &shader;
24+
return true;
25+
}
26+
27+
void Renderer::SetWireframe(const bool wireframe) { _polygonMode = wireframe ? vk::PolygonMode::eLine : vk::PolygonMode::eFill; }
28+
29+
void Renderer::SetLineWidth(const float width)
30+
{
31+
if (_renderPass == nullptr) { return; }
32+
const auto limits = _renderPass->get_render_device().get_gpu().properties.limits.lineWidthRange;
33+
_lineWidth = std::clamp(width, limits[0], limits[1]);
34+
}
35+
36+
void Renderer::Draw(const std::uint32_t vertices)
37+
{
38+
if (!IsRendering() || _shader == nullptr) { return; }
39+
40+
const auto pipelineParams = PipelinePool::Params{
41+
.colourFormat = _renderPass->get_color_format(),
42+
.polygonMode = _polygonMode,
43+
};
44+
const auto pipeline = _resourcePool->pipelinePool.GetPipeline(*_shader, pipelineParams);
45+
if (!pipeline) { return; }
46+
47+
if (_pipeline != pipeline)
48+
{
49+
_pipeline = pipeline;
50+
_renderPass->bind_pipeline(_pipeline);
51+
}
52+
53+
const auto commandBuffer = _renderPass->get_command_buffer();
54+
commandBuffer.setLineWidth(_lineWidth);
55+
commandBuffer.draw(vertices, 1, 0, 0);
56+
}
57+
} // namespace tkge::graphics

lib/src/graphics/resource_pool.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#include <klib/hash_combine.hpp>
2+
#include <tkge/graphics/resource_pool.hpp>
3+
#include <vulkan/vulkan_hash.hpp>
4+
5+
namespace tkge::graphics
6+
{
7+
PipelinePool::PipelinePool(gsl::not_null<const kvf::RenderDevice*> renderDevice, const vk::SampleCountFlagBits framebufferSamples)
8+
: _renderDevice(renderDevice), _framebufferSamples(framebufferSamples)
9+
{
10+
// TODO: descriptor set layouts
11+
_pipelineLayout = renderDevice->get_device().createPipelineLayoutUnique({});
12+
}
13+
14+
vk::Pipeline PipelinePool::GetPipeline(const Shader& shader, const Params& params)
15+
{
16+
const auto key = klib::make_combined_hash(shader.GetHash(), params.colourFormat, params.polygonMode, params.topology);
17+
auto it = _pipelines.find(key);
18+
if (it != _pipelines.end()) { return *it->second; }
19+
20+
const auto pipelineState = kvf::PipelineState{
21+
.vertex_bindings = {},
22+
.vertex_attributes = {},
23+
.vertex_shader = shader.VertexModule(),
24+
.fragment_shader = shader.FragmentModule(),
25+
.topology = params.topology,
26+
.polygon_mode = params.polygonMode,
27+
};
28+
const auto pipelineFormat = kvf::PipelineFormat{
29+
.samples = _framebufferSamples,
30+
.color = params.colourFormat,
31+
};
32+
auto ret = _renderDevice->create_pipeline(*_pipelineLayout, pipelineState, pipelineFormat);
33+
if (!ret) { return {}; }
34+
35+
it = _pipelines.insert({key, std::move(ret)}).first;
36+
return *it->second;
37+
}
38+
39+
} // namespace tkge::graphics

0 commit comments

Comments
 (0)