summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCédric Mocquillon <cedric.mocquillon@gmail.com>2024-02-18 19:26:23 +0100
committerCédric Mocquillon <cedric.mocquillon@gmail.com>2024-02-18 19:26:23 +0100
commit9c50fd3f44d4f77d2e744d057c0764355a1b9203 (patch)
tree69effc1aa25c76ac461ee18280a9992a351e9bc6
parent8545fb920e216ea4cb639e712e5cb80c5e101ee3 (diff)
Bunch of stuffBindlessTest
-rw-r--r--components/CMakeLists.txt4
-rw-r--r--components/resource/scenemanager.cpp157
-rw-r--r--components/resource/scenemanager.hpp4
-rw-r--r--components/shader/shadervisitor.cpp5
-rw-r--r--components/shader/shadervisitor.hpp4
-rw-r--r--files/shaders/compatibility/objects.frag20
-rw-r--r--files/shaders/compatibility/objects.vert8
7 files changed, 197 insertions, 5 deletions
diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt
index 317786e96a..2e50daf542 100644
--- a/components/CMakeLists.txt
+++ b/components/CMakeLists.txt
@@ -42,6 +42,10 @@ list (APPEND COMPONENT_FILES "${OpenMW_BINARY_DIR}/${VERSION_CPP_FILE}")
# source files
+add_component_dir (bindlesstexture
+ bindlesstexture
+ )
+
add_component_dir (lua
luastate scriptscontainer asyncpackage utilpackage serialization configuration l10n storage utf8
shapes/box inputactions
diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp
index 787f2e8441..03c235c56c 100644
--- a/components/resource/scenemanager.cpp
+++ b/components/resource/scenemanager.cpp
@@ -22,6 +22,7 @@
#include <components/nifosg/controller.hpp>
#include <components/nifosg/nifloader.hpp>
+#include <components/nifosg/particle.hpp>
#include <components/nif/niffile.hpp>
@@ -33,13 +34,16 @@
#include <components/vfs/manager.hpp>
#include <components/vfs/pathutil.hpp>
+#include <components/vfs/recursivedirectoryiterator.hpp>
#include <components/sceneutil/clone.hpp>
#include <components/sceneutil/controller.hpp>
#include <components/sceneutil/depth.hpp>
#include <components/sceneutil/extradata.hpp>
#include <components/sceneutil/lightmanager.hpp>
+#include <components/sceneutil/morphgeometry.hpp>
#include <components/sceneutil/optimizer.hpp>
+#include <components/sceneutil/riggeometry.hpp>
#include <components/sceneutil/riggeometryosgaextension.hpp>
#include <components/sceneutil/util.hpp>
#include <components/sceneutil/visitor.hpp>
@@ -352,6 +356,139 @@ namespace Resource
std::vector<osg::ref_ptr<SceneUtil::RigGeometryHolder>> mRigGeometryHolders;
};
+ class TextureAtlasVisitor : public osg::NodeVisitor
+ {
+ public:
+ /// default to traversing all children.
+ TextureAtlasVisitor()
+ : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
+ {
+ }
+
+ void apply(osg::Node& node) override
+ {
+ bool pushedStateState = false;
+
+ osg::StateSet* ss = node.getStateSet();
+ if (ss)
+ pushedStateState = pushStateSet(ss);
+
+ traverse(node);
+
+ if (pushedStateState)
+ popStateSet();
+ }
+
+ void apply(osg::Drawable& node) override
+ {
+ if (auto rig = dynamic_cast<SceneUtil::RigGeometry*>(&node))
+ return apply(*rig->getSourceGeometry());
+ if (auto morph = dynamic_cast<SceneUtil::MorphGeometry*>(&node))
+ return apply(*morph->getSourceGeometry());
+
+ if (dynamic_cast<NifOsg::ParticleSystem*>(&node))
+ return;
+ //if (dynamic_cast<osgParticle::ParticleSystemUpdater*>(&node))
+ // toskip = true;
+ if (dynamic_cast<osgParticle::ParticleProcessor*>(&node))
+ return;
+ if (dynamic_cast<osgParticle::Particle*>(&node))
+ return;
+
+ bool pushedStateState = false;
+
+ osg::StateSet* ss = node.getStateSet();
+ if (ss)
+ pushedStateState = pushStateSet(ss);
+
+ [&] {
+ osg::Geometry* geom = node.asGeometry();
+ if (!geom || _statesetStack.empty())
+ return;
+
+ const osg::StateSet::TextureAttributeList& tal = _statesetStack.back()->getTextureAttributeList();
+ for (unsigned int unit = 0; unit < tal.size(); ++unit)
+ {
+ osg::ref_ptr<osg::Texture2D> texture = dynamic_cast<osg::Texture2D*>(
+ _statesetStack.back()->getTextureAttribute(unit, osg::StateAttribute::TEXTURE));
+ if (!texture)
+ continue;
+
+ auto it
+ = std::find(mTexture->_textureList.begin(), mTexture->_textureList.end(), texture->getImage());
+ if (it == mTexture->_textureList.end())
+ continue;
+ unsigned int d = std::distance(mTexture->_textureList.begin(), it);
+ auto indices = new osg::IntArray(geom->getVertexArray()->getNumElements());
+ for (unsigned int i = 0; i < geom->getVertexArray()->getNumElements(); ++i)
+ (*indices)[i] = d;
+ geom->setVertexAttribArray(7, indices, osg::Array::BIND_PER_VERTEX);
+ }
+ }();
+
+
+ if (pushedStateState)
+ popStateSet();
+ }
+
+ osg::ref_ptr<BindlessTexture> mTexture;
+
+ protected:
+ bool pushStateSet(osg::StateSet* stateset)
+ {
+ const osg::StateSet::TextureAttributeList& tal = stateset->getTextureAttributeList();
+
+ // if no textures ignore
+ if (tal.empty())
+ return false;
+
+ bool pushStateState = false;
+
+ // if already in stateset list ignore
+ if (_statesetMap.count(stateset) > 0)
+ {
+ pushStateState = true;
+ }
+ else
+ {
+ bool containsTexture2D = false;
+ for (unsigned int unit = 0; unit < tal.size(); ++unit)
+ {
+ osg::Texture2D* texture2D = dynamic_cast<osg::Texture2D*>(
+ stateset->getTextureAttribute(unit, osg::StateAttribute::TEXTURE));
+ if (texture2D)
+ {
+ containsTexture2D = true;
+ _textures.insert(texture2D);
+ }
+ }
+
+ if (containsTexture2D)
+ {
+ _statesetMap[stateset];
+ pushStateState = true;
+ }
+ }
+
+ if (pushStateState)
+ {
+ _statesetStack.push_back(stateset);
+ }
+
+ return pushStateState;
+ }
+ void popStateSet() { _statesetStack.pop_back(); }
+
+ typedef std::set<osg::Drawable*> Drawables;
+ typedef std::map<osg::StateSet*, Drawables> StateSetMap;
+ typedef std::set<osg::Texture2D*> Textures;
+ typedef std::vector<osg::StateSet*> StateSetStack;
+
+ StateSetMap _statesetMap;
+ StateSetStack _statesetStack;
+ Textures _textures;
+ };
+
SceneManager::SceneManager(const VFS::Manager* vfs, Resource::ImageManager* imageManager,
Resource::NifFileManager* nifFileManager, double expiryDelay)
: ResourceManager(vfs, expiryDelay)
@@ -374,6 +511,17 @@ namespace Resource
, mUnRefImageDataAfterApply(false)
, mParticleSystemMask(~0u)
{
+ mBuffer = BindlessBuffer::Make(4800);
+
+ BindlessTexture::TextureList images;
+ images.reserve(4800);
+ for (auto const& tex : vfs->getRecursiveDirectoryIterator("textures/"))
+ {
+ auto image = imageManager->getImage(tex);
+ if (image->s() > 16 || image->t() > 16)
+ images.push_back(image);
+ }
+ mTexture = new BindlessTexture(mBuffer, images);
}
void SceneManager::setForceShaders(bool force)
@@ -900,6 +1048,11 @@ namespace Resource
SceneUtil::ReplaceDepthVisitor replaceDepthVisitor;
loaded->accept(replaceDepthVisitor);
+ TextureAtlasVisitor tav;
+ tav.mTexture = mTexture;
+ loaded->accept(tav);
+ shareState(loaded);
+
osg::ref_ptr<Shader::ShaderVisitor> shaderVisitor(createShaderVisitor());
loaded->accept(*shaderVisitor);
@@ -1134,6 +1287,10 @@ namespace Resource
shaderVisitor->setAdjustCoverageForAlphaTest(mAdjustCoverageForAlphaTest);
shaderVisitor->setSupportsNormalsRT(mSupportsNormalsRT);
shaderVisitor->setWeatherParticleOcclusion(mWeatherParticleOcclusion);
+
+ shaderVisitor->mBuffer = mBuffer;
+ shaderVisitor->mTexture = mTexture;
+
return shaderVisitor;
}
}
diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp
index 12900441de..57fdc028be 100644
--- a/components/resource/scenemanager.hpp
+++ b/components/resource/scenemanager.hpp
@@ -12,6 +12,7 @@
#include "resourcemanager.hpp"
#include <components/sceneutil/lightmanager.hpp>
+#include <components/bindlesstexture/bindlesstexture.hpp>
#include <filesystem>
namespace VFS
@@ -230,6 +231,9 @@ namespace Resource
void setWeatherParticleOcclusion(bool value) { mWeatherParticleOcclusion = value; }
private:
+ osg::ref_ptr<BindlessBuffer> mBuffer;
+ osg::ref_ptr <BindlessTexture> mTexture;
+
osg::ref_ptr<Shader::ShaderVisitor> createShaderVisitor(const std::string& shaderPrefix = "objects");
osg::ref_ptr<osg::Node> loadErrorMarker();
osg::ref_ptr<osg::Node> cloneErrorMarker();
diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp
index e281f64448..d89ca2aedc 100644
--- a/components/shader/shadervisitor.cpp
+++ b/components/shader/shadervisitor.cpp
@@ -361,6 +361,10 @@ namespace Shader
mRequirements.back().mTexStageRequiringTangents = unit;
}
diffuseMap = texture;
+ if (!writableStateSet)
+ writableStateSet = getWritableStateSet(node);
+ writableStateSet->setTextureAttribute(unit, mTexture, osg::StateAttribute::ON);
+ writableStateSet->setAttributeAndModes(mBuffer->Binding(), osg::StateAttribute::ON);
}
else if (texName == "specularMap")
specularMap = texture;
@@ -739,6 +743,7 @@ namespace Shader
shaderPrefix = mDefaultShaderPrefix;
auto program = mShaderManager.getProgram(shaderPrefix, defineMap, mProgramTemplate);
+ program->addBindAttribLocation("index", 7);
writableStateSet->setAttributeAndModes(program, osg::StateAttribute::ON);
addedState->setAttributeAndModes(std::move(program));
diff --git a/components/shader/shadervisitor.hpp b/components/shader/shadervisitor.hpp
index a8e79ec995..2d8dcf9bb8 100644
--- a/components/shader/shadervisitor.hpp
+++ b/components/shader/shadervisitor.hpp
@@ -3,6 +3,7 @@
#include <osg/NodeVisitor>
#include <osg/Program>
+#include <components/bindlesstexture/bindlesstexture.hpp>
namespace Resource
{
@@ -63,6 +64,9 @@ namespace Shader
void pushRequirements(osg::Node& node);
void popRequirements();
+ osg::ref_ptr<BindlessBuffer> mBuffer;
+ osg::ref_ptr<BindlessTexture> mTexture;
+
private:
bool mForceShaders;
bool mAllowedToModifyStateSets;
diff --git a/files/shaders/compatibility/objects.frag b/files/shaders/compatibility/objects.frag
index 56c7abf27c..b1767b6ef6 100644
--- a/files/shaders/compatibility/objects.frag
+++ b/files/shaders/compatibility/objects.frag
@@ -1,4 +1,6 @@
-#version 120
+#version 450 compatibility
+#extension GL_ARB_bindless_texture : require
+#extension GL_NV_gpu_shader5 : require // uint64_t
#pragma import_defines(FORCE_OPAQUE, DISTORTION)
#if @useUBO
@@ -14,6 +16,13 @@ uniform sampler2D diffuseMap;
varying vec2 diffuseMapUV;
#endif
+flat in int textureIndex;
+
+layout (binding = 0, std140) uniform TEXTURE_BLOCK
+{
+ uint64_t tex[4096];
+};
+
#if @darkMap
uniform sampler2D darkMap;
varying vec2 darkMapUV;
@@ -124,12 +133,15 @@ void main()
// only offset diffuse and normal maps for now, other textures are more likely to be using a completely different UV set
vec2 offset = vec2(0.0);
+ int tIndex = (int)(textureIndex);
+ sampler2D myText = sampler2D(tex[tIndex]);
+
#if @parallax || @diffuseParallax
#if @parallax
float height = texture2D(normalMap, normalMapUV).a;
float flipY = (passTangent.w > 0.0) ? -1.f : 1.f;
#else
- float height = texture2D(diffuseMap, diffuseMapUV).a;
+ float height = texture2D(myText, diffuseMapUV).a;
// FIXME: shouldn't be necessary, but in this path false-positives are common
float flipY = -1.f;
#endif
@@ -139,7 +151,7 @@ void main()
vec2 screenCoords = gl_FragCoord.xy / screenRes;
#if @diffuseMap
- gl_FragData[0] = texture2D(diffuseMap, diffuseMapUV + offset);
+ gl_FragData[0] = texture2D(myText, diffuseMapUV + offset);
#if defined(DISTORTION) && DISTORTION
gl_FragData[0].a = getDiffuseColor().a;
@@ -150,7 +162,7 @@ vec2 screenCoords = gl_FragCoord.xy / screenRes;
#if @diffuseParallax
gl_FragData[0].a = 1.0;
#else
- gl_FragData[0].a *= coveragePreservingAlphaScale(diffuseMap, diffuseMapUV + offset);
+ gl_FragData[0].a *= coveragePreservingAlphaScale(myText, diffuseMapUV + offset);
#endif
#else
gl_FragData[0] = vec4(1.0);
diff --git a/files/shaders/compatibility/objects.vert b/files/shaders/compatibility/objects.vert
index 081ff909cf..2401f35a06 100644
--- a/files/shaders/compatibility/objects.vert
+++ b/files/shaders/compatibility/objects.vert
@@ -1,4 +1,6 @@
-#version 120
+#version 450 compatibility
+#extension GL_ARB_bindless_texture : require
+#extension GL_NV_gpu_shader5 : require // uint64_t
#if @useUBO
#extension GL_ARB_uniform_buffer_object : require
@@ -8,6 +10,9 @@
#extension GL_EXT_gpu_shader4: require
#endif
+attribute float index;
+flat out int textureIndex;
+
#include "lib/core/vertex.h.glsl"
#if @diffuseMap
varying vec2 diffuseMapUV;
@@ -94,6 +99,7 @@ void main(void)
passViewPos = viewPos.xyz;
passNormal = gl_Normal.xyz;
normalToViewMatrix = gl_NormalMatrix;
+ textureIndex = (int)(index + 0.5);
#if @normalMap || @diffuseParallax
passTangent = gl_MultiTexCoord7.xyzw;