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

Add Graphics::RenderInstance, bind instance SSBO during draw #21

Merged
merged 1 commit into from
Feb 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 22 additions & 5 deletions App/Src/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#include <Tkge/Engine.hpp>
#include <Tkge/Graphics/Shader.hpp>
#include <klib/assert.hpp>
#include <kvf/time.hpp>
#include <cmath>
#include <exception>
#include <print>

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

static constexpr auto Vertices = std::array{
Tkge::Graphics::Vertex{.position = {-200.0f, -200.0f}, .colour = kvf::red_v.to_vec4()},
Tkge::Graphics::Vertex{.position = {200.0f, -200.0f}, .colour = kvf::green_v.to_vec4()},
Tkge::Graphics::Vertex{.position = {200.0f, 200.0f}, .colour = kvf::blue_v.to_vec4()},
Tkge::Graphics::Vertex{.position = {-200.0f, 200.0f}, .colour = kvf::yellow_v.to_vec4()},
Tkge::Graphics::Vertex{.position = {-200.0f, -200.0f}},
Tkge::Graphics::Vertex{.position = {200.0f, -200.0f}},
Tkge::Graphics::Vertex{.position = {200.0f, 200.0f}},
Tkge::Graphics::Vertex{.position = {-200.0f, 200.0f}},
};

static constexpr auto Indices = std::array{
Expand All @@ -66,13 +68,28 @@ namespace
.indices = Indices,
};

auto instances = std::array<Tkge::Graphics::RenderInstance, 2>{};
instances[0].transform.position.x = -250.0f;
instances[0].tint = kvf::cyan_v;
instances[1].transform.position.x = 250.0f;
instances[1].tint = kvf::yellow_v;

auto wireframe = false;
auto lineWidth = 3.0f;

auto deltaTime = kvf::DeltaTime{};
auto elapsed = kvf::Seconds{};

while (engine.IsRunning())
{
engine.NextFrame();

const auto dt = deltaTime.tick();
elapsed += dt;

instances[0].tint.w = kvf::Color::to_u8((0.5f * std::sin(elapsed.count())) + 0.5f);
instances[1].tint.w = kvf::Color::to_u8((0.5f * std::sin(-elapsed.count())) + 0.5f);

if (ImGui::Begin("Misc"))
{
ImGui::Checkbox("wireframe", &wireframe);
Expand All @@ -85,7 +102,7 @@ namespace
renderer.BindShader(shader);
renderer.SetLineWidth(lineWidth);
renderer.SetWireframe(wireframe);
renderer.Draw(Primitive);
renderer.Draw(Primitive, instances);
}

engine.Present();
Expand Down
Binary file modified Assets/Shaders/Default.vert
Binary file not shown.
12 changes: 12 additions & 0 deletions Lib/Include/Tkge/Graphics/RenderInstance.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#pragma once
#include <Tkge/Transform.hpp>
#include <kvf/color.hpp>

namespace Tkge::Graphics
{
struct RenderInstance
{
Transform transform{};
kvf::Color tint{kvf::white_v};
};
} // namespace Tkge::Graphics
13 changes: 11 additions & 2 deletions Lib/Include/Tkge/Graphics/Renderer.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once
#include <Tkge/Graphics/Primitive.hpp>
#include <Tkge/Graphics/RenderInstance.hpp>
#include <Tkge/Graphics/ResourcePool.hpp>
#include <Tkge/Transform.hpp>
#include <kvf/render_pass.hpp>
Expand All @@ -26,15 +27,22 @@ namespace Tkge::Graphics
void SetLineWidth(float width);
void SetWireframe(bool wireframe);

void Draw(const Primitive& primitive);
void Draw(const Primitive& primitive, std::span<const RenderInstance> instances);

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

Transform view{};

private:
struct Std430Instance
{
glm::mat4 model;
glm::vec4 tint;
};

void UpdateInstances(std::span<const RenderInstance> instances);
[[nodiscard]] bool WriteSets() const;
void BindVboAndDraw(const Primitive& primitive) const;
void BindVboAndDraw(const Primitive& primitive, std::uint32_t instances) const;

kvf::RenderPass* _renderPass{};
IResourcePool* _resourcePool{};
Expand All @@ -45,5 +53,6 @@ namespace Tkge::Graphics
vk::Pipeline _pipeline{};
vk::PolygonMode _polygonMode{vk::PolygonMode::eFill};
float _lineWidth{1.0f};
std::vector<Std430Instance> _instances{};
};
} // namespace Tkge::Graphics
6 changes: 4 additions & 2 deletions Lib/Src/Detail/PipelinePool.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,12 @@ namespace Tkge::Detail
{
static constexpr auto StageFlags = vk::ShaderStageFlagBits::eAllGraphics;
// set 0: builtin
auto set0 = std::array<vk::DescriptorSetLayoutBinding, 1>{};
auto set0 = std::array<vk::DescriptorSetLayoutBinding, 2>{};
// set 0, binding 0: view
set0[0].setBinding(0).setDescriptorCount(1).setDescriptorType(vk::DescriptorType::eUniformBuffer).setStageFlags(StageFlags);
// TODO: instances, texture bindings
// set 0, binding 1: instances
set0[1].setBinding(1).setDescriptorCount(1).setDescriptorType(vk::DescriptorType::eStorageBuffer).setStageFlags(StageFlags);
// TODO: texture bindings

// TODO: set 1: user data

Expand Down
19 changes: 17 additions & 2 deletions Lib/Src/Glsl/Default.vert
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
#version 450 core

struct Instance
{
mat4 model;
vec4 tint;
};

layout (location = 0) in vec2 aPos;
layout (location = 1) in vec4 aColour;
layout (location = 2) in vec2 aUv;
Expand All @@ -9,11 +15,20 @@ layout (set = 0, binding = 0) uniform View
mat4 matVP;
};

layout (set = 0, binding = 1) readonly buffer Instances
{
Instance instances[];
};

layout (location = 0) out vec4 outColour;

void main()
{
outColour = aColour;
const Instance instance = instances[gl_InstanceIndex];

const vec4 worldPos = instance.model * vec4(aPos, 0.0, 1.0);

outColour = aColour * instance.tint;

gl_Position = matVP * vec4(aPos, 0.0, 1.0);
gl_Position = matVP * worldPos;
}
32 changes: 24 additions & 8 deletions Lib/Src/Graphics/Renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,18 @@ namespace Tkge::Graphics
return true;
}

void Renderer::SetWireframe(const bool wireframe) { _polygonMode = wireframe ? vk::PolygonMode::eLine : vk::PolygonMode::eFill; }

void Renderer::SetLineWidth(const float width)
{
if (_renderPass == nullptr) { return; }
const auto limits = _renderPass->get_render_device().get_gpu().properties.limits.lineWidthRange;
_lineWidth = std::clamp(width, limits[0], limits[1]);
}

void Renderer::Draw(const Primitive& primitive)
void Renderer::SetWireframe(const bool wireframe) { _polygonMode = wireframe ? vk::PolygonMode::eLine : vk::PolygonMode::eFill; }

void Renderer::Draw(const Primitive& primitive, std::span<const RenderInstance> instances)
{
if (!IsRendering() || _shader == nullptr || primitive.vertices.empty()) { return; }
if (!IsRendering() || _shader == nullptr || primitive.vertices.empty() || instances.empty()) { return; }

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

UpdateInstances(instances);
if (!WriteSets()) { return; }

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

BindVboAndDraw(primitive);
BindVboAndDraw(primitive, std::uint32_t(instances.size()));
}

void Renderer::UpdateInstances(std::span<const RenderInstance> instances)
{
_instances.clear();
_instances.reserve(instances.size());
for (const auto& instance : instances)
{
_instances.push_back(Std430Instance{.model = instance.transform.ToModel(), .tint = instance.tint.to_linear()});
}
}

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

const auto instanceSpan = std::span{_instances};
auto& ssbo01 = _resourcePool->AllocateBuffer(vk::BufferUsageFlagBits::eStorageBuffer, instanceSpan.size_bytes());
kvf::util::overwrite(ssbo01, instanceSpan);
pushBufferWrite(descriptorSets[0], 1, ssbo01, vk::DescriptorType::eStorageBuffer);

const auto writeSpan = std::span{descriptorWrites.data(), descriptorWrites.size()};
renderDevice.get_device().updateDescriptorSets(writeSpan, {});

Expand All @@ -100,7 +116,7 @@ namespace Tkge::Graphics
return true;
}

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

commandBuffer.bindVertexBuffers(0, vertexBuffer.get_buffer(), vk::DeviceSize{});
if (primitive.indices.empty()) { commandBuffer.draw(std::uint32_t(primitive.vertices.size()), 1, 0, 0); }
if (primitive.indices.empty()) { commandBuffer.draw(std::uint32_t(primitive.vertices.size()), instances, 0, 0); }
else
{
commandBuffer.bindIndexBuffer(vertexBuffer.get_buffer(), vertSize, vk::IndexType::eUint32);
commandBuffer.drawIndexed(std::uint32_t(primitive.indices.size()), 1, 0, 0, 0);
commandBuffer.drawIndexed(std::uint32_t(primitive.indices.size()), instances, 0, 0, 0);
}
}
} // namespace Tkge::Graphics