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

Commit 105f32e

Browse files
committed
Add Graphics::RenderInstance, bind instance SSBO during draw
1 parent fe7e646 commit 105f32e

File tree

7 files changed

+90
-19
lines changed

7 files changed

+90
-19
lines changed

App/Src/Main.cpp

+22-5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
#include <Tkge/Engine.hpp>
33
#include <Tkge/Graphics/Shader.hpp>
44
#include <klib/assert.hpp>
5+
#include <kvf/time.hpp>
6+
#include <cmath>
57
#include <exception>
68
#include <print>
79

@@ -51,10 +53,10 @@ namespace
5153
if (!shader.Load(renderDevice.get_device(), vertexSpirV, fragmentSpirV)) { throw std::runtime_error{"Failed to load shaders"}; }
5254

5355
static constexpr auto Vertices = std::array{
54-
Tkge::Graphics::Vertex{.position = {-200.0f, -200.0f}, .colour = kvf::red_v.to_vec4()},
55-
Tkge::Graphics::Vertex{.position = {200.0f, -200.0f}, .colour = kvf::green_v.to_vec4()},
56-
Tkge::Graphics::Vertex{.position = {200.0f, 200.0f}, .colour = kvf::blue_v.to_vec4()},
57-
Tkge::Graphics::Vertex{.position = {-200.0f, 200.0f}, .colour = kvf::yellow_v.to_vec4()},
56+
Tkge::Graphics::Vertex{.position = {-200.0f, -200.0f}},
57+
Tkge::Graphics::Vertex{.position = {200.0f, -200.0f}},
58+
Tkge::Graphics::Vertex{.position = {200.0f, 200.0f}},
59+
Tkge::Graphics::Vertex{.position = {-200.0f, 200.0f}},
5860
};
5961

6062
static constexpr auto Indices = std::array{
@@ -66,13 +68,28 @@ namespace
6668
.indices = Indices,
6769
};
6870

71+
auto instances = std::array<Tkge::Graphics::RenderInstance, 2>{};
72+
instances[0].transform.position.x = -250.0f;
73+
instances[0].tint = kvf::cyan_v;
74+
instances[1].transform.position.x = 250.0f;
75+
instances[1].tint = kvf::yellow_v;
76+
6977
auto wireframe = false;
7078
auto lineWidth = 3.0f;
7179

80+
auto deltaTime = kvf::DeltaTime{};
81+
auto elapsed = kvf::Seconds{};
82+
7283
while (engine.IsRunning())
7384
{
7485
engine.NextFrame();
7586

87+
const auto dt = deltaTime.tick();
88+
elapsed += dt;
89+
90+
instances[0].tint.w = kvf::Color::to_u8((0.5f * std::sin(elapsed.count())) + 0.5f);
91+
instances[1].tint.w = kvf::Color::to_u8((0.5f * std::sin(-elapsed.count())) + 0.5f);
92+
7693
if (ImGui::Begin("Misc"))
7794
{
7895
ImGui::Checkbox("wireframe", &wireframe);
@@ -85,7 +102,7 @@ namespace
85102
renderer.BindShader(shader);
86103
renderer.SetLineWidth(lineWidth);
87104
renderer.SetWireframe(wireframe);
88-
renderer.Draw(Primitive);
105+
renderer.Draw(Primitive, instances);
89106
}
90107

91108
engine.Present();

Assets/Shaders/Default.vert

980 Bytes
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#pragma once
2+
#include <Tkge/Transform.hpp>
3+
#include <kvf/color.hpp>
4+
5+
namespace Tkge::Graphics
6+
{
7+
struct RenderInstance
8+
{
9+
Transform transform{};
10+
kvf::Color tint{kvf::white_v};
11+
};
12+
} // namespace Tkge::Graphics

Lib/Include/Tkge/Graphics/Renderer.hpp

+11-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22
#include <Tkge/Graphics/Primitive.hpp>
3+
#include <Tkge/Graphics/RenderInstance.hpp>
34
#include <Tkge/Graphics/ResourcePool.hpp>
45
#include <Tkge/Transform.hpp>
56
#include <kvf/render_pass.hpp>
@@ -26,15 +27,22 @@ namespace Tkge::Graphics
2627
void SetLineWidth(float width);
2728
void SetWireframe(bool wireframe);
2829

29-
void Draw(const Primitive& primitive);
30+
void Draw(const Primitive& primitive, std::span<const RenderInstance> instances);
3031

3132
explicit operator bool() const { return IsRendering(); }
3233

3334
Transform view{};
3435

3536
private:
37+
struct Std430Instance
38+
{
39+
glm::mat4 model;
40+
glm::vec4 tint;
41+
};
42+
43+
void UpdateInstances(std::span<const RenderInstance> instances);
3644
[[nodiscard]] bool WriteSets() const;
37-
void BindVboAndDraw(const Primitive& primitive) const;
45+
void BindVboAndDraw(const Primitive& primitive, std::uint32_t instances) const;
3846

3947
kvf::RenderPass* _renderPass{};
4048
IResourcePool* _resourcePool{};
@@ -45,5 +53,6 @@ namespace Tkge::Graphics
4553
vk::Pipeline _pipeline{};
4654
vk::PolygonMode _polygonMode{vk::PolygonMode::eFill};
4755
float _lineWidth{1.0f};
56+
std::vector<Std430Instance> _instances{};
4857
};
4958
} // namespace Tkge::Graphics

Lib/Src/Detail/PipelinePool.hpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,12 @@ namespace Tkge::Detail
7575
{
7676
static constexpr auto StageFlags = vk::ShaderStageFlagBits::eAllGraphics;
7777
// set 0: builtin
78-
auto set0 = std::array<vk::DescriptorSetLayoutBinding, 1>{};
78+
auto set0 = std::array<vk::DescriptorSetLayoutBinding, 2>{};
7979
// set 0, binding 0: view
8080
set0[0].setBinding(0).setDescriptorCount(1).setDescriptorType(vk::DescriptorType::eUniformBuffer).setStageFlags(StageFlags);
81-
// TODO: instances, texture bindings
81+
// set 0, binding 1: instances
82+
set0[1].setBinding(1).setDescriptorCount(1).setDescriptorType(vk::DescriptorType::eStorageBuffer).setStageFlags(StageFlags);
83+
// TODO: texture bindings
8284

8385
// TODO: set 1: user data
8486

Lib/Src/Glsl/Default.vert

+17-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
#version 450 core
22

3+
struct Instance
4+
{
5+
mat4 model;
6+
vec4 tint;
7+
};
8+
39
layout (location = 0) in vec2 aPos;
410
layout (location = 1) in vec4 aColour;
511
layout (location = 2) in vec2 aUv;
@@ -9,11 +15,20 @@ layout (set = 0, binding = 0) uniform View
915
mat4 matVP;
1016
};
1117

18+
layout (set = 0, binding = 1) readonly buffer Instances
19+
{
20+
Instance instances[];
21+
};
22+
1223
layout (location = 0) out vec4 outColour;
1324

1425
void main()
1526
{
16-
outColour = aColour;
27+
const Instance instance = instances[gl_InstanceIndex];
28+
29+
const vec4 worldPos = instance.model * vec4(aPos, 0.0, 1.0);
30+
31+
outColour = aColour * instance.tint;
1732

18-
gl_Position = matVP * vec4(aPos, 0.0, 1.0);
33+
gl_Position = matVP * worldPos;
1934
}

Lib/Src/Graphics/Renderer.cpp

+24-8
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,18 @@ namespace Tkge::Graphics
2929
return true;
3030
}
3131

32-
void Renderer::SetWireframe(const bool wireframe) { _polygonMode = wireframe ? vk::PolygonMode::eLine : vk::PolygonMode::eFill; }
33-
3432
void Renderer::SetLineWidth(const float width)
3533
{
3634
if (_renderPass == nullptr) { return; }
3735
const auto limits = _renderPass->get_render_device().get_gpu().properties.limits.lineWidthRange;
3836
_lineWidth = std::clamp(width, limits[0], limits[1]);
3937
}
4038

41-
void Renderer::Draw(const Primitive& primitive)
39+
void Renderer::SetWireframe(const bool wireframe) { _polygonMode = wireframe ? vk::PolygonMode::eLine : vk::PolygonMode::eFill; }
40+
41+
void Renderer::Draw(const Primitive& primitive, std::span<const RenderInstance> instances)
4242
{
43-
if (!IsRendering() || _shader == nullptr || primitive.vertices.empty()) { return; }
43+
if (!IsRendering() || _shader == nullptr || primitive.vertices.empty() || instances.empty()) { return; }
4444

4545
const auto fixedState = PipelineFixedState{
4646
.colourFormat = _renderPass->get_color_format(),
@@ -56,11 +56,22 @@ namespace Tkge::Graphics
5656
_renderPass->bind_pipeline(_pipeline);
5757
}
5858

59+
UpdateInstances(instances);
5960
if (!WriteSets()) { return; }
6061

6162
_renderPass->get_command_buffer().setViewport(0, _viewport);
6263

63-
BindVboAndDraw(primitive);
64+
BindVboAndDraw(primitive, std::uint32_t(instances.size()));
65+
}
66+
67+
void Renderer::UpdateInstances(std::span<const RenderInstance> instances)
68+
{
69+
_instances.clear();
70+
_instances.reserve(instances.size());
71+
for (const auto& instance : instances)
72+
{
73+
_instances.push_back(Std430Instance{.model = instance.transform.ToModel(), .tint = instance.tint.to_linear()});
74+
}
6475
}
6576

6677
bool Renderer::WriteSets() const
@@ -91,6 +102,11 @@ namespace Tkge::Graphics
91102
kvf::util::overwrite(ubo00, matVP);
92103
pushBufferWrite(descriptorSets[0], 0, ubo00, vk::DescriptorType::eUniformBuffer);
93104

105+
const auto instanceSpan = std::span{_instances};
106+
auto& ssbo01 = _resourcePool->AllocateBuffer(vk::BufferUsageFlagBits::eStorageBuffer, instanceSpan.size_bytes());
107+
kvf::util::overwrite(ssbo01, instanceSpan);
108+
pushBufferWrite(descriptorSets[0], 1, ssbo01, vk::DescriptorType::eStorageBuffer);
109+
94110
const auto writeSpan = std::span{descriptorWrites.data(), descriptorWrites.size()};
95111
renderDevice.get_device().updateDescriptorSets(writeSpan, {});
96112

@@ -100,7 +116,7 @@ namespace Tkge::Graphics
100116
return true;
101117
}
102118

103-
void Renderer::BindVboAndDraw(const Primitive& primitive) const
119+
void Renderer::BindVboAndDraw(const Primitive& primitive, const std::uint32_t instances) const
104120
{
105121
const auto vertSize = primitive.vertices.size_bytes();
106122
const auto vboSize = vertSize + primitive.indices.size_bytes();
@@ -112,11 +128,11 @@ namespace Tkge::Graphics
112128
commandBuffer.setLineWidth(_lineWidth);
113129

114130
commandBuffer.bindVertexBuffers(0, vertexBuffer.get_buffer(), vk::DeviceSize{});
115-
if (primitive.indices.empty()) { commandBuffer.draw(std::uint32_t(primitive.vertices.size()), 1, 0, 0); }
131+
if (primitive.indices.empty()) { commandBuffer.draw(std::uint32_t(primitive.vertices.size()), instances, 0, 0); }
116132
else
117133
{
118134
commandBuffer.bindIndexBuffer(vertexBuffer.get_buffer(), vertSize, vk::IndexType::eUint32);
119-
commandBuffer.drawIndexed(std::uint32_t(primitive.indices.size()), 1, 0, 0, 0);
135+
commandBuffer.drawIndexed(std::uint32_t(primitive.indices.size()), instances, 0, 0, 0);
120136
}
121137
}
122138
} // namespace Tkge::Graphics

0 commit comments

Comments
 (0)