summaryrefslogtreecommitdiff
path: root/gfx/gl
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2023-04-22 19:06:42 +0100
committerDan Goodliffe <dan@randomdan.homeip.net>2023-04-22 19:06:42 +0100
commitd1f79b4c438ebf0822741e103b2cb06bdee4514e (patch)
treea4d574d12cd81d5e33886ce7ca961f7dbe872fcf /gfx/gl
parentRename lots of shader files (diff)
parentKeep the instance unused vector sorted and binary search it (diff)
downloadilt-d1f79b4c438ebf0822741e103b2cb06bdee4514e.tar.bz2
ilt-d1f79b4c438ebf0822741e103b2cb06bdee4514e.tar.xz
ilt-d1f79b4c438ebf0822741e103b2cb06bdee4514e.zip
Merge branch 'instancing'
Diffstat (limited to 'gfx/gl')
-rw-r--r--gfx/gl/instanceVertices.h211
-rw-r--r--gfx/gl/sceneRenderer.cpp6
-rw-r--r--gfx/gl/sceneShader.cpp29
-rw-r--r--gfx/gl/sceneShader.h3
-rw-r--r--gfx/gl/shaders/dynamicPointInst.vs21
-rw-r--r--gfx/gl/shaders/spotLight.vs2
-rw-r--r--gfx/gl/vertexArrayObject.hpp107
7 files changed, 319 insertions, 60 deletions
diff --git a/gfx/gl/instanceVertices.h b/gfx/gl/instanceVertices.h
new file mode 100644
index 0000000..228020d
--- /dev/null
+++ b/gfx/gl/instanceVertices.h
@@ -0,0 +1,211 @@
+#pragma once
+
+#include "glArrays.h"
+#include <iterator>
+#include <span>
+#include <special_members.hpp>
+#include <utility>
+#include <vector>
+
+template<typename T> class InstanceVertices {
+public:
+ InstanceVertices(size_t initialSize = 16)
+ {
+ allocBuffer(initialSize);
+ }
+
+ class [[nodiscard]] InstanceProxy {
+ public:
+ InstanceProxy(InstanceVertices * iv, std::size_t idx) : instances {iv}, index {idx} { }
+ InstanceProxy(InstanceProxy && other) : instances {std::exchange(other.instances, nullptr)}, index {other.index}
+ {
+ }
+ NO_COPY(InstanceProxy);
+
+ ~InstanceProxy()
+ {
+ if (instances) {
+ instances->release(index);
+ }
+ }
+
+ InstanceProxy &
+ operator=(InstanceProxy && other)
+ {
+ if (instances) {
+ instances->release(index);
+ }
+ instances = std::exchange(other.instances, nullptr);
+ index = other.index;
+ return *this;
+ }
+ template<typename U>
+ T &
+ operator=(U && v)
+ {
+ return instances->at(index) = std::forward<U>(v);
+ }
+
+ [[nodiscard]]
+ operator T &()
+ {
+ return instances->at(index);
+ }
+ [[nodiscard]] operator const T &() const
+ {
+ return instances->at(index);
+ }
+ [[nodiscard]] T *
+ get()
+ {
+ return &instances->at(index);
+ }
+ [[nodiscard]] const T *
+ get() const
+ {
+ return &instances->at(index);
+ }
+ [[nodiscard]] T *
+ operator->()
+ {
+ return get();
+ }
+ [[nodiscard]] const T *
+ operator->() const
+ {
+ return get();
+ }
+ [[nodiscard]] T &
+ operator*()
+ {
+ return instances->at(index);
+ }
+ [[nodiscard]] const T &
+ operator*() const
+ {
+ return instances->at(index);
+ }
+
+ private:
+ InstanceVertices<T> * instances;
+ std::size_t index;
+ };
+
+ template<typename... Params>
+ [[nodiscard]] InstanceProxy
+ acquire(Params &&... params)
+ {
+ map();
+ if (!unused.empty()) {
+ auto idx = unused.back();
+ unused.pop_back();
+ index[idx] = next++;
+ new (&at(idx)) T(std::forward<Params>(params)...);
+ return InstanceProxy {this, idx};
+ }
+ if (next >= capacity) {
+ resize(capacity * 2);
+ }
+ index.emplace_back(next++);
+ new (data + index.back()) T(std::forward<Params>(params)...);
+ return InstanceProxy {this, index.size() - 1};
+ }
+
+ [[nodiscard]] const auto &
+ bufferName() const
+ {
+ return buffer;
+ }
+
+ [[nodiscard]] auto
+ count() const
+ {
+ unmap();
+ return next;
+ }
+
+protected:
+ friend InstanceProxy;
+
+ void
+ release(const size_t pidx)
+ {
+ // Destroy p's object
+ at(pidx).~T();
+ if (--next != index[pidx]) {
+ // Move last object into p's slot
+ new (&at(pidx)) T {std::move(data[next])};
+ (data[next]).~T();
+ *std::find_if(index.begin(), index.end(), [this](const auto & i) {
+ return i == next && !std::binary_search(unused.begin(), unused.end(), &i - index.data());
+ }) = index[pidx];
+ }
+ if (pidx == index.size() - 1) {
+ index.pop_back();
+ }
+ else {
+ // Remember p.index is free index now, keeping it sorted
+ unused.insert(std::upper_bound(unused.begin(), unused.end(), pidx), pidx);
+ }
+ }
+
+ void
+ allocBuffer(std::size_t newCapacity)
+ {
+ glBindBuffer(GL_ARRAY_BUFFER, buffer);
+ glBufferData(GL_ARRAY_BUFFER, static_cast<GLsizeiptr>(sizeof(T) * newCapacity), nullptr, GL_DYNAMIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ capacity = newCapacity;
+ data = nullptr;
+ }
+
+ void
+ resize(size_t newCapacity)
+ {
+ const auto maintain = std::min(newCapacity, capacity);
+ std::vector<T> existing;
+ const auto maintaind = static_cast<typename decltype(existing)::difference_type>(maintain);
+ existing.reserve(maintain);
+ map();
+ std::move(data, data + maintain, std::back_inserter(existing));
+ allocBuffer(newCapacity);
+ map();
+ std::move(existing.begin(), existing.begin() + maintaind, data);
+ capacity = newCapacity;
+ }
+
+ [[nodiscard]] T &
+ at(size_t pindex)
+ {
+ map();
+ return data[index[pindex]];
+ }
+
+ void
+ map() const
+ {
+ if (!data) {
+ data = static_cast<T *>(glMapNamedBuffer(buffer, GL_READ_WRITE));
+ }
+ }
+
+ void
+ unmap() const
+ {
+ if (data) {
+ glUnmapNamedBuffer(buffer);
+ data = nullptr;
+ }
+ }
+
+ glBuffer buffer;
+ mutable T * data {};
+ // Size of buffer
+ std::size_t capacity {};
+ // # used of capacity
+ std::size_t next {};
+ // Index into buffer given to nth proxy
+ std::vector<size_t> index;
+ // List of free spaces in index
+ std::vector<size_t> unused;
+};
diff --git a/gfx/gl/sceneRenderer.cpp b/gfx/gl/sceneRenderer.cpp
index 873dc5b..6542bea 100644
--- a/gfx/gl/sceneRenderer.cpp
+++ b/gfx/gl/sceneRenderer.cpp
@@ -18,7 +18,7 @@ SceneRenderer::SceneRenderer(glm::ivec2 s, GLuint o) :
lighting {lighting_vs, lighting_fs}, shadowMapper {{2048, 2048}}
{
shader.setViewPort({0, 0, size.x, size.y});
- VertexArrayObject<glm::i8vec4>::configure(displayVAO, displayVBO, displayVAOdata);
+ VertexArrayObject {displayVAO}.addAttribs<glm::i8vec4>(displayVBO, displayVAOdata);
glBindFramebuffer(GL_FRAMEBUFFER, gBuffer);
const auto configuregdata
@@ -128,8 +128,8 @@ SceneRenderer::renderQuad() const
SceneRenderer::DirectionalLightProgram::DirectionalLightProgram() :
Program {lighting_vs, directionalLight_fs}, directionLoc {*this, "lightDirection"},
colourLoc {*this, "lightColour"}, lightViewProjectionLoc {*this, "lightViewProjection"},
- lightViewProjectionCountLoc {*this, "lightViewProjectionCount"}, lightViewShadowMapRegionLoc {
- *this, "shadowMapRegion"}
+ lightViewProjectionCountLoc {*this, "lightViewProjectionCount"},
+ lightViewShadowMapRegionLoc {*this, "shadowMapRegion"}
{
}
diff --git a/gfx/gl/sceneShader.cpp b/gfx/gl/sceneShader.cpp
index bcd0590..00d9826 100644
--- a/gfx/gl/sceneShader.cpp
+++ b/gfx/gl/sceneShader.cpp
@@ -8,6 +8,7 @@
#include <gfx/gl/shaders/gs-pointLight.h>
#include <gfx/gl/shaders/gs-spotLight.h>
#include <gfx/gl/shaders/vs-dynamicPoint.h>
+#include <gfx/gl/shaders/vs-dynamicPointInst.h>
#include <gfx/gl/shaders/vs-fixedPoint.h>
#include <gfx/gl/shaders/vs-pointLight.h>
#include <gfx/gl/shaders/vs-spotLight.h>
@@ -18,13 +19,17 @@
#include <location.hpp>
#include <maths.h>
-SceneShader::SceneShader() : landmass {fixedPoint_vs, landmass_fs}, absolute {fixedPoint_vs, material_fs} { }
+SceneShader::SceneShader() :
+ basicInst {dynamicPointInst_vs, material_fs}, landmass {fixedPoint_vs, landmass_fs},
+ absolute {fixedPoint_vs, material_fs}
+{
+}
void
SceneShader::setViewProjection(const glm::mat4 & viewProjection) const
{
- for (const auto & prog :
- std::array<const SceneProgram *, 6> {&basic, &water, &landmass, &absolute, &pointLight, &spotLight}) {
+ for (const auto & prog : std::array<const SceneProgram *, 7> {
+ &basic, &basicInst, &water, &landmass, &absolute, &pointLight, &spotLight}) {
prog->setViewProjection(viewProjection);
}
}
@@ -32,8 +37,8 @@ SceneShader::setViewProjection(const glm::mat4 & viewProjection) const
void
SceneShader::setViewPort(const glm::ivec4 & viewPort) const
{
- for (const auto & prog :
- std::array<const SceneProgram *, 6> {&basic, &water, &landmass, &absolute, &pointLight, &spotLight}) {
+ for (const auto & prog : std::array<const SceneProgram *, 7> {
+ &basic, &basicInst, &water, &landmass, &absolute, &pointLight, &spotLight}) {
prog->setViewPort(viewPort);
}
}
@@ -83,7 +88,7 @@ SceneShader::WaterProgram::use(float waveCycle) const
SceneShader::PointLightShader::PointLightShader() :
SceneProgram {pointLight_vs, pointLight_gs, pointLight_fs}, colourLoc {*this, "colour"}, kqLoc {*this, "kq"}
{
- VertexArrayObject<glm::vec3>::configure(va, b);
+ VertexArrayObject {va}.addAttribs<glm::vec3>(b);
}
void
@@ -94,16 +99,16 @@ SceneShader::PointLightShader::add(const glm::vec3 & position, const glm::vec3 &
glBindBuffer(GL_ARRAY_BUFFER, b);
glUniform3fv(colourLoc, 1, glm::value_ptr(colour));
glUniform1f(kqLoc, kq);
- glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(glm::vec3), glm::value_ptr(position));
+ glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3), glm::value_ptr(position), GL_DYNAMIC_DRAW);
glDrawArrays(GL_POINTS, 0, 1);
}
SceneShader::SpotLightShader::SpotLightShader() :
- SceneProgram {spotLight_vs, spotLight_gs, spotLight_fs}, colourLoc {*this, "colour"}, kqLoc {*this, "kq"},
- arcLoc {*this, "arc"}
+ SceneProgram {spotLight_vs, spotLight_gs, spotLight_fs}, directionLoc {*this, "v_direction"},
+ colourLoc {*this, "colour"}, kqLoc {*this, "kq"}, arcLoc {*this, "arc"}
{
using v3pair = std::pair<glm::vec3, glm::vec3>;
- VertexArrayObject<v3pair>::configure<&v3pair::first, &v3pair::second>(va, b);
+ VertexArrayObject {va}.addAttribs<v3pair, &v3pair::first, &v3pair::second>(b);
}
void
@@ -114,9 +119,9 @@ SceneShader::SpotLightShader::add(const glm::vec3 & position, const glm::vec3 &
glBindVertexArray(va);
glBindBuffer(GL_ARRAY_BUFFER, b);
glUniform3fv(colourLoc, 1, glm::value_ptr(colour));
+ glUniform3fv(directionLoc, 1, glm::value_ptr(direction));
glUniform1f(kqLoc, kq);
glUniform1f(arcLoc, arc);
- glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(glm::vec3), glm::value_ptr(position));
- glBufferSubData(GL_ARRAY_BUFFER, sizeof(glm::vec3), sizeof(glm::vec3), glm::value_ptr(direction));
+ glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3), glm::value_ptr(position), GL_DYNAMIC_DRAW);
glDrawArrays(GL_POINTS, 0, 1);
}
diff --git a/gfx/gl/sceneShader.h b/gfx/gl/sceneShader.h
index ed1bb79..ead184e 100644
--- a/gfx/gl/sceneShader.h
+++ b/gfx/gl/sceneShader.h
@@ -69,6 +69,7 @@ class SceneShader {
const float arc) const;
private:
+ UniformLocation directionLoc;
UniformLocation colourLoc;
UniformLocation kqLoc;
UniformLocation arcLoc;
@@ -81,7 +82,7 @@ public:
BasicProgram basic;
WaterProgram water;
- AbsolutePosProgram landmass, absolute;
+ AbsolutePosProgram basicInst, landmass, absolute;
PointLightShader pointLight;
SpotLightShader spotLight;
diff --git a/gfx/gl/shaders/dynamicPointInst.vs b/gfx/gl/shaders/dynamicPointInst.vs
new file mode 100644
index 0000000..1c66979
--- /dev/null
+++ b/gfx/gl/shaders/dynamicPointInst.vs
@@ -0,0 +1,21 @@
+#version 330 core
+
+include(`meshIn.glsl')
+layout(location = 5) in mat4 model;
+include(`materialInterface.glsl')
+
+uniform mat4 viewProjection;
+
+void
+main()
+{
+ vec4 worldPos = model * vec4(position, 1.0);
+
+ FragPos = worldPos.xyz;
+ TexCoords = texCoord;
+ Normal = (model * vec4(normal, 0.0)).xyz;
+ Colour = colour;
+ Material = material;
+
+ gl_Position = viewProjection * worldPos;
+}
diff --git a/gfx/gl/shaders/spotLight.vs b/gfx/gl/shaders/spotLight.vs
index e648553..dca0854 100644
--- a/gfx/gl/shaders/spotLight.vs
+++ b/gfx/gl/shaders/spotLight.vs
@@ -1,8 +1,8 @@
#version 330 core
layout(location = 0) in vec3 v_position;
-layout(location = 1) in vec3 v_direction;
+uniform vec3 v_direction;
uniform vec3 colour;
uniform float kq;
uniform float arc;
diff --git a/gfx/gl/vertexArrayObject.hpp b/gfx/gl/vertexArrayObject.hpp
index 5b9fc60..7ded03e 100644
--- a/gfx/gl/vertexArrayObject.hpp
+++ b/gfx/gl/vertexArrayObject.hpp
@@ -2,50 +2,65 @@
#include "collections.hpp"
#include "gl_traits.hpp"
+#include "special_members.hpp"
#include <GL/glew.h>
-#include <glm/common.hpp>
-template<typename Vertex> class VertexArrayObject {
+class VertexArrayObject {
public:
- template<auto Vertex::*... attribs>
- static void
- configure(const GLuint arrayObject, const GLuint arrayBuffer, const GLuint indexBuffer,
- const SequentialCollection<Vertex> auto & vertices, const SequentialCollection<unsigned int> auto & indices)
+ template<typename T> [[nodiscard]] VertexArrayObject(const T & arrayObject)
{
glBindVertexArray(arrayObject);
-
- configure_attribs<attribs...>(arrayBuffer);
- data(vertices, arrayBuffer, GL_ARRAY_BUFFER);
- data(indices, indexBuffer, GL_ELEMENT_ARRAY_BUFFER);
-
+ }
+ ~VertexArrayObject()
+ {
glBindVertexArray(0);
}
+ NO_MOVE(VertexArrayObject);
+ NO_COPY(VertexArrayObject);
- template<auto Vertex::*... attribs>
- static void
- configure(const GLuint arrayObject, const GLuint arrayBuffer, const SequentialCollection<Vertex> auto & vertices)
- {
- glBindVertexArray(arrayObject);
+ template<typename m, typename T> struct MP {
+ constexpr MP(m T::*p) : P {p} { }
+ operator void *() const
+ {
+ return &(static_cast<T *>(nullptr)->*P);
+ }
+ m T::*P;
+ using value_type = m;
+ };
+ template<typename m, typename T> MP(m T::*) -> MP<m, T>;
- configure_attribs<attribs...>(arrayBuffer);
+ template<typename VertexT, MP... attribs>
+ VertexArrayObject &
+ addAttribs(const GLuint arrayBuffer, const SequentialCollection<VertexT> auto & vertices, const GLuint divisor = 0)
+ {
+ addAttribs<VertexT, attribs...>(arrayBuffer, divisor);
data(vertices, arrayBuffer, GL_ARRAY_BUFFER);
-
- glBindVertexArray(0);
+ return *this;
}
- template<auto Vertex::*... attribs>
- static void
- configure(const GLuint arrayObject, const GLuint arrayBuffer)
+ template<typename VertexT, MP... attribs>
+ VertexArrayObject &
+ addAttribs(const GLuint arrayBuffer, const GLuint divisor = 0)
{
- glBindVertexArray(arrayObject);
+ configure_attribs<VertexT, attribs...>(arrayBuffer, divisor);
+ return *this;
+ }
- configure_attribs<attribs...>(arrayBuffer);
- glBufferData(GL_ARRAY_BUFFER, static_cast<GLsizeiptr>(sizeof(Vertex)), nullptr, GL_DYNAMIC_DRAW);
+ template<typename Indices>
+ VertexArrayObject &
+ addIndices(const GLuint arrayBuffer, const Indices & indices)
+ {
+ data(indices, arrayBuffer, GL_ELEMENT_ARRAY_BUFFER);
+ return *this;
+ }
- glBindVertexArray(0);
+ VertexArrayObject &
+ addIndices(const GLuint arrayBuffer)
+ {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, arrayBuffer);
+ return *this;
}
-private:
template<typename Data>
static void
data(const Data & data, const GLuint arrayBuffer, GLenum target)
@@ -55,34 +70,40 @@ private:
glBufferData(target, static_cast<GLsizeiptr>(sizeof(Value) * data.size()), data.data(), GL_STATIC_DRAW);
}
- template<typename T>
- static void
- set_pointer(const GLuint vertexArrayId, const void * ptr)
+private:
+ template<typename VertexT, typename T>
+ static auto
+ set_pointer(const GLuint vertexArrayId, const void * ptr, const GLuint divisor)
{
- glEnableVertexAttribArray(vertexArrayId);
using traits = gl_traits<T>;
- traits::vertexAttribFunc(vertexArrayId, traits::size, traits::type, sizeof(Vertex), ptr);
+ const auto usedAttribs
+ = traits::vertexAttribFunc(vertexArrayId, traits::size, traits::type, sizeof(VertexT), ptr);
+ for (GLuint i {}; i < usedAttribs; i++) {
+ glEnableVertexAttribArray(vertexArrayId + i);
+ glVertexAttribDivisor(vertexArrayId + i, divisor);
+ }
+ return usedAttribs;
}
- template<auto Vertex::*attrib>
- static void
- set_pointer(const GLuint vertexArrayId)
+ template<typename VertexT, MP attrib>
+ static auto
+ set_pointer(const GLuint vertexArrayId, const GLuint divisor)
{
- set_pointer<std::decay_t<decltype(std::declval<Vertex>().*attrib)>>(
- vertexArrayId, &(static_cast<const Vertex *>(nullptr)->*attrib));
+ return set_pointer<VertexT, typename decltype(attrib)::value_type>(vertexArrayId, attrib, divisor);
}
- template<auto Vertex::*... attribs>
- static void
- configure_attribs(const GLuint arrayBuffer)
+ template<typename VertexT, MP... attribs>
+ void
+ configure_attribs(const GLuint arrayBuffer, const GLuint divisor)
{
glBindBuffer(GL_ARRAY_BUFFER, arrayBuffer);
if constexpr (sizeof...(attribs) == 0) {
- set_pointer<Vertex>(0, nullptr);
+ vertexArrayId += set_pointer<VertexT, VertexT>(vertexArrayId, nullptr, divisor);
}
else {
- GLuint vertexArrayId {};
- (set_pointer<attribs>(vertexArrayId++), ...);
+ ((vertexArrayId += set_pointer<VertexT, attribs>(vertexArrayId, divisor)), ...);
}
}
+
+ GLuint vertexArrayId {};
};