From c403a71564def731f4d3b80d6ff63f08aa3c7ea3 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Wed, 11 Mar 2026 20:45:05 +0000 Subject: Reuse vertex array objects for common structures with DSA Slashes the number of VAOs required and the amount of setup required. --- game/scenary/foliage.cpp | 35 +++++++++++++++++++++-------------- game/scenary/foliage.h | 4 ++-- game/scenary/illuminator.cpp | 42 ++++++++++++++++++++++++++---------------- game/scenary/illuminator.h | 5 ++--- 4 files changed, 51 insertions(+), 35 deletions(-) (limited to 'game/scenary') diff --git a/game/scenary/foliage.cpp b/game/scenary/foliage.cpp index b5b409e..ff00af4 100644 --- a/game/scenary/foliage.cpp +++ b/game/scenary/foliage.cpp @@ -20,6 +20,8 @@ namespace { } } +std::weak_ptr Foliage::commonInstanceVAO, Foliage::commonInstancePointVAO; + std::any Foliage::createAt(const Location & position) const { @@ -38,10 +40,15 @@ Foliage::postLoad() { texture = getTexture(); glDebugScope _ {0}; - bodyMesh->configureVAO(instanceVAO, 0) - .addAttribs(1); - instancePointVAO.configure().addAttribs(0); - + if (!(instanceVAO = commonInstanceVAO.lock())) { + commonInstanceVAO = instanceVAO = std::make_shared(); + bodyMesh->configureVAO(*instanceVAO, 0) + .addAttribs(1); + } + if (!(instancePointVAO = commonInstancePointVAO.lock())) { + commonInstancePointVAO = instancePointVAO = std::make_shared(); + instancePointVAO->configure().addAttribs(0); + } const auto & size = bodyMesh->getDimensions().size; billboardSize = billboardTextureSizeForObject(size); ShadowStenciller::configureStencilTexture(shadowStencil, {billboardSize, billboardSize}); @@ -93,7 +100,7 @@ void Foliage::render(const SceneShader & shader, const Frustum &) const { if (instancePartitions.first) { - glDebugScope _ {instanceVAO}; + glDebugScope _ {*instanceVAO}; std::ignore = instances.size(); if (const auto count = instancePartitions.first - instancePartitions.second.first) { glDebugScope _ {0, "Billboard"}; @@ -102,8 +109,8 @@ Foliage::render(const SceneShader & shader, const Frustum &) const billboard[0].bind(0); billboard[1].bind(1); billboard[2].bind(2); - glBindVertexArray(instancePointVAO); - instancePointVAO.useBuffer(0, instances); + glBindVertexArray(*instancePointVAO); + instancePointVAO->useBuffer(0, instances); glDrawArrays(GL_POINTS, static_cast(instancePartitions.second.first), static_cast(count)); glBindVertexArray(0); } @@ -113,8 +120,8 @@ Foliage::render(const SceneShader & shader, const Frustum &) const if (texture) { texture->bind(0); } - instanceVAO.useBuffer(1, instances); - bodyMesh->drawInstanced(instanceVAO, static_cast(count)); + instanceVAO->useBuffer(1, instances); + bodyMesh->drawInstanced(*instanceVAO, static_cast(count)); } } } @@ -123,15 +130,15 @@ void Foliage::shadows(const ShadowMapper & mapper, const Frustum &) const { if (instancePartitions.second.second) { - glDebugScope _ {instanceVAO}; + glDebugScope _ {*instanceVAO}; std::ignore = instances.size(); if (const auto count = instancePartitions.second.second - instancePartitions.second.first) { glDebugScope _ {0, "Billboard"}; const auto dimensions = bodyMesh->getDimensions(); mapper.stencilShadowProgram.use(dimensions.centre, dimensions.size); shadowStencil.bind(0); - glBindVertexArray(instancePointVAO); - instancePointVAO.useBuffer(0, instances); + glBindVertexArray(*instancePointVAO); + instancePointVAO->useBuffer(0, instances); glDrawArrays(GL_POINTS, static_cast(instancePartitions.second.first), static_cast(count)); glBindVertexArray(0); } @@ -144,8 +151,8 @@ Foliage::shadows(const ShadowMapper & mapper, const Frustum &) const else { mapper.dynamicPointInst.use(); } - instanceVAO.useBuffer(1, instances); - bodyMesh->drawInstanced(instanceVAO, static_cast(count)); + instanceVAO->useBuffer(1, instances); + bodyMesh->drawInstanced(*instanceVAO, static_cast(count)); } } } diff --git a/game/scenary/foliage.h b/game/scenary/foliage.h index bf98d55..c599649 100644 --- a/game/scenary/foliage.h +++ b/game/scenary/foliage.h @@ -12,8 +12,8 @@ class Location; class Foliage : public Asset, public Renderable, public StdTypeDefs { Mesh::Ptr bodyMesh; Texture::Ptr texture; - glVertexArray instanceVAO; - glVertexArray instancePointVAO; + std::shared_ptr instanceVAO, instancePointVAO; + static std::weak_ptr commonInstanceVAO, commonInstancePointVAO; public: [[nodiscard]] std::any createAt(const Location &) const override; diff --git a/game/scenary/illuminator.cpp b/game/scenary/illuminator.cpp index a0ea5be..4398853 100644 --- a/game/scenary/illuminator.cpp +++ b/game/scenary/illuminator.cpp @@ -5,6 +5,9 @@ static_assert(std::is_constructible_v); +std::weak_ptr Illuminator::commonInstanceVAO, Illuminator::commonInstancesSpotLightVAO, + Illuminator::commonInstancesPointLightVAO; + std::any Illuminator::createAt(const Location & position) const { @@ -41,25 +44,32 @@ Illuminator::postLoad() } texture = getTexture(); glDebugScope _ {0}; - bodyMesh->configureVAO(instanceVAO, 0) - .addAttribs(1); - if (!spotLight.empty()) { - instancesSpotLightVAO.emplace(); - instancesSpotLightVAO->configure() - .addAttribs(0) + if (!(instanceVAO = commonInstanceVAO.lock())) { + commonInstanceVAO = instanceVAO = std::make_shared(); + bodyMesh->configureVAO(*instanceVAO, 0) .addAttribs(1); + } + if (!spotLight.empty()) { + if (!(instancesSpotLightVAO = commonInstancesSpotLightVAO.lock())) { + commonInstancesSpotLightVAO = instancesSpotLightVAO = std::make_shared(); + instancesSpotLightVAO->configure() + .addAttribs(0) + .addAttribs(1); + } std::transform( spotLight.begin(), spotLight.end(), std::back_inserter(spotLightInstances), [this](const auto & s) { return instancesSpotLight.acquire(*s); }); } if (!pointLight.empty()) { - instancesPointLightVAO.emplace(); - instancesPointLightVAO->configure() - .addAttribs(0) - .addAttribs(1); + if (!(instancesPointLightVAO = commonInstancesPointLightVAO.lock())) { + commonInstancesPointLightVAO = instancesPointLightVAO = std::make_shared(); + instancesPointLightVAO->configure() + .addAttribs(0) + .addAttribs(1); + } std::transform( pointLight.begin(), pointLight.end(), std::back_inserter(pointLightInstances), [this](const auto & s) { return instancesPointLight.acquire(*s); @@ -71,13 +81,13 @@ void Illuminator::render(const SceneShader & shader, const Frustum &) const { if (const auto count = instances.size()) { - glDebugScope _ {instanceVAO}; + glDebugScope _ {*instanceVAO}; shader.basicInst.use(); if (texture) { texture->bind(0); } - instanceVAO.useBuffer(1, instances); - bodyMesh->drawInstanced(instanceVAO, static_cast(count)); + instanceVAO->useBuffer(1, instances); + bodyMesh->drawInstanced(*instanceVAO, static_cast(count)); } } @@ -85,7 +95,7 @@ void Illuminator::lights(const SceneShader & shader) const { if (const auto count = instances.size()) { - glDebugScope _ {instanceVAO}; + glDebugScope _ {*instanceVAO}; if (const auto scount = instancesSpotLight.size()) { glDebugScope _ {*instancesSpotLightVAO, "Spot lights"}; shader.spotLightInst.use(); diff --git a/game/scenary/illuminator.h b/game/scenary/illuminator.h index 200ba40..7b6e7ad 100644 --- a/game/scenary/illuminator.h +++ b/game/scenary/illuminator.h @@ -11,8 +11,8 @@ class Location; class Illuminator : public Asset, public Renderable, public StdTypeDefs { Mesh::Ptr bodyMesh; Texture::Ptr texture; - glVertexArray instanceVAO; - std::optional instancesSpotLightVAO, instancesPointLightVAO; + std::shared_ptr instanceVAO, instancesSpotLightVAO, instancesPointLightVAO; + static std::weak_ptr commonInstanceVAO, commonInstancesSpotLightVAO, commonInstancesPointLightVAO; public: [[nodiscard]] std::any createAt(const Location &) const override; @@ -42,7 +42,6 @@ public: bool persist(Persistence::PersistenceStore & store) override; }; -public: using LocationVertex = std::pair; mutable InstanceVertices instances; mutable InstanceVertices instancesSpotLight; -- cgit v1.3