factored out texture GPU data loading

improved texture buffer and layer retrieval
using draw commands 1:1 with meshes
This commit is contained in:
devZoGok
2026-07-08 12:08:03 +03:00
parent e448f7003e
commit f457c69d36
11 changed files with 85 additions and 158 deletions
+3 -4
View File
@@ -16,13 +16,12 @@ namespace vb01{
struct FontAsset : public Asset{
struct Glyph{
int id;
u8 *data;
Vector2 size, bearing;
u32 advance;
int layerId;
int id, bufferId, layerId;
Vector2 size, bearing;
Glyph(int i, u8 *d, Vector2 s, Vector2 b, u32 adv, int lid) : id(i), data(d), size(s), bearing(b), advance(adv), layerId(lid){}
Glyph(int i, u8 *d, Vector2 s, Vector2 b, u32 adv, int bid, int lid) : id(i), data(d), size(s), bearing(b), advance(adv), bufferId(bid), layerId(lid){}
};
const Glyph& getGlyph(int);
+2 -2
View File
@@ -36,7 +36,6 @@ namespace vb01{
vector<FontAsset::Glyph> glyphs;
Root *root = Root::getSingleton();
u32 *buffer = root->getGuiTextureBuffer();
for(u16 i = firstChar; i < lastChar; i++){
if(FT_Load_Char(face, i, FT_LOAD_RENDER)){
@@ -50,9 +49,10 @@ namespace vb01{
Vector2(face->glyph->bitmap.width, face->glyph->bitmap.rows),
Vector2(face->glyph->bitmap_left, face->glyph->bitmap_top),
face->glyph->advance.x,
-1,
-1
);
root->initTextureDataOnGpu(buffer, glyph.data, glyph.size.x, glyph.size.y, glyph.layerId);
root->initTextureDataOnGpu(glyph.data, glyph.size.x, glyph.size.y, glyph.bufferId, glyph.layerId, false);
glyphs.push_back(glyph);
}
+6 -3
View File
@@ -5,18 +5,21 @@
namespace vb01{
struct ImageAsset : public Asset{
ImageAsset(std::string p, u8 *img, int w, int h, int nc, int lid) :
ImageAsset(std::string p, u8 *img, int w, int h, int nc, int bid, int lid, bool ltg) :
image(img),
width(w),
height(h),
numChannels(nc),
layerId(lid)
bufferId(lid),
layerId(lid),
loadedToGpu(ltg)
{
this->path = p;
}
u8 *image;
int width, height, numChannels, layerId;
int width, height, numChannels, bufferId, layerId;
bool loadedToGpu = true;
};
}
+4 -7
View File
@@ -17,15 +17,12 @@ namespace vb01{
Asset* ImageReader::readAsset(string path){
stbi_set_flip_vertically_on_load(flip);
int width, height, numChannels, layerId;
int width, height, numChannels, bufferId, layerId;
u8 *data = stbi_load(path.c_str(), &width, &height, &numChannels, 0);
if(loadToGpu){
Root *root = Root::getSingleton();
u32 *texBuffer = (sceneImage ? root->getMeshTextureBuffer() : root->getGuiTextureBuffer());
root->initTextureDataOnGpu(texBuffer, data, width, height, layerId);
}
if(loadToGpu)
Root::getSingleton()->initTextureDataOnGpu(data, width, height, bufferId, layerId, sceneImage);
return new ImageAsset(path, data, width, height, numChannels, layerId);
return new ImageAsset(path, data, width, height, numChannels, bufferId, layerId, loadToGpu);
}
}
+3 -2
View File
@@ -1,7 +1,7 @@
#version 460 core
const bool checkLights=false;
in flat int ID;
in flat int drawId, instanceId;
in vec3 fragPos;
in vec3 tan;
in vec3 biTan;
@@ -81,7 +81,8 @@ float getShadow(int id){
}
void main(){
int id = ID;
int id = drawId;
vec4 diffuseColor = vec4(objData[id].diffuseColor[0], objData[id].diffuseColor[1], objData[id].diffuseColor[2], objData[id].diffuseColor[3]);
vec4 finalColor = diffuseColor;
+5 -4
View File
@@ -19,7 +19,7 @@ layout (location = 6) in ivec4 aBoneIndices;
out vec3 fragPos, norm, tan, biTan;
out vec2 texCoords;
out int ID;
out int drawId, instanceId;
struct Bone{
float angle;
@@ -80,10 +80,10 @@ float getWeight(Bone bone){
}
void main(){
int id = gl_DrawID;
vec4 vertPos = vec4(aPos, 1);
bool anyWeights = false;
int id = gl_DrawID + gl_InstanceID;
mat4 model = objData[id].model;
mat3 normalMat = mat3(transpose(inverse(model)));
norm = (normalMat * aNorm);
@@ -147,5 +147,6 @@ void main(){
gl_Position = viewProj * model * vertPos;
fragPos = vec3(model * vertPos);
texCoords = aTexCoords;
ID = id;
drawId = gl_DrawID;
instanceId = gl_InstanceID;
}
+43 -119
View File
@@ -76,12 +76,6 @@ namespace vb01{
guiPlaneTextureBuffer = new u32;
glGenTextures(1, guiPlaneTextureBuffer);
meshTextureBuffer = new u32[NUM_MAX_TEXTURE_UNITS];
glGenTextures(NUM_MAX_TEXTURE_UNITS, meshTextureBuffer);
guiTextureBuffer = new u32[NUM_MAX_TEXTURE_UNITS];
glGenTextures(NUM_MAX_TEXTURE_UNITS, guiTextureBuffer);
phongShader = new Shader(libPath + "phong4");
guiShader = new Shader(libPath + "gui");
@@ -144,42 +138,49 @@ namespace vb01{
}
//TODO check loading of textures with different dimensions
void Root::initTextureDataOnGpu(u32 *textureBuffer, u8 *data, int width, int height, int &layerId){
bool present = false;
void Root::initTextureDataOnGpu(u8 *data, int width, int height, int &bufferId, int &layerId, bool scene){
int textureUnitId = -1;
vector<TextureUnitGpuData> &textureData = (scene ? meshTextureData : guiTextureData);
for(pair<int, int> &p : currTextureDims)
if(p.first == width && p.second == height){
present = true;
for(int i = 0; i < textureData.size(); i++)
if(textureData[i].width == width && textureData[i].height == height){
textureUnitId = i;
break;
}
if(!present) currTextureDims.push_back(make_pair(width, height));
if(textureUnitId == -1){
textureData.push_back(TextureUnitGpuData(width, height));
textureUnitId = textureData.size() - 1;
glGenTextures(1, &textureData[textureUnitId].buffer);
}
AssetManager *assetManager = AssetManager::getSingleton();
vector<Asset*> assets = assetManager->getAssets(assetManager->getImageFormats());
for(int i = 0; i < currTextureDims.size(); i++){
for(int i = 0; i < textureData.size(); i++){
vector<ImageAsset*> imgAssets;
pair<int, int> &resPair = currTextureDims[i];
TextureUnitGpuData &texData = textureData[i];
for(Asset *asset : assets){
ImageAsset *a = (ImageAsset*)asset;
if(a->width == resPair.first && a->height == resPair.second)
if(a->loadedToGpu && a->width == texData.width && a->height == texData.height)
imgAssets.push_back((ImageAsset*)asset);
}
//layerId = currNumLayers, currNumLayers++;
glBindTexture(GL_TEXTURE_2D_ARRAY, texData.buffer);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGB, texData.width, texData.height, imgAssets.size() + 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D_ARRAY, textureBuffer[i]);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGB, resPair.first, resPair.second, imgAssets.size() + 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
for(int j = 0; j < imgAssets.size(); j++)
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, j, imgAssets[j]->width, imgAssets[j]->height, 1, GL_RGB, GL_UNSIGNED_BYTE, imgAssets[j]->image);
for(int i = 0; i < imgAssets.size(); i++)
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, i, width, height, 1, GL_RGB, GL_UNSIGNED_BYTE, imgAssets[i]->image);
if(resPair.first == width && resPair.second == height){
if(textureUnitId == i){
bufferId = i;
int lid = 0 + (imgAssets.size() == 0 ? 0 : 1);
layerId = lid;
texData.numLayers++;
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, lid, width, height, 1, GL_RGB, GL_UNSIGNED_BYTE, data);
}
@@ -187,6 +188,7 @@ namespace vb01{
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
}
@@ -296,8 +298,20 @@ namespace vb01{
bool lightingEnabled = ((Material::BoolUniform*)mat->getUniform("lightingEnabled"))->value;
for(int i = 0; i < drawCmdMeshes.size(); i++)
if(*(drawCmdMeshes[i]) == meshData)
drawCmds[i].instanceCount++;
if(*(drawCmdMeshes[i]) == meshData){
int sum = 0;
for(int j = 0; j < i; j++)
sum += 3 * drawCmdMeshes[j]->numTris;
DrawElementsIndirectCommand cmd;
cmd.count = 3 * meshData.numTris;
cmd.instanceCount = 1;
cmd.firstIndex = sum;
cmd.baseVertex = 0;
cmd.baseInstance = 0;
drawCmds.push_back(cmd);
}
ObjectVertexData ovd;
ovd.viewProj = projView;
@@ -422,18 +436,7 @@ namespace vb01{
u32 vertSize = sizeof(MeshData::GpuVertex), indexSize = sizeof(u32);
if(updateDrawCommands){
DrawElementsIndirectCommand drawCmd;
drawCmd.count = 3 * meshData.numTris;
drawCmd.instanceCount = 0;
drawCmd.firstIndex = currentIndices.size();
drawCmd.baseVertex = currentGpuVertices.size();
drawCmd.baseInstance = 0;
drawCmds.push_back(drawCmd);
drawCmdMeshes.push_back(&meshData);
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, drawCmdBuffer);
glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(DrawElementsIndirectCommand) * drawCmds.size(), drawCmds.data(), GL_DYNAMIC_DRAW);
int currNumIndices = currentIndices.size();
for(int i = 0; i < 3 * meshData.numTris; i++)
@@ -471,18 +474,6 @@ namespace vb01{
//Texture *brightTexture = new Texture(width, height, false);
}
void Root::addMeshes(Node *rootNode){
vector<Node*> descendants;
rootNode->getDescendants(descendants);
vector<Mesh*> meshes;
for(Node *desc : descendants){
vector<Mesh*> m = desc->getMeshes();
meshes.insert(meshes.end(), m.begin(), m.end());
}
}
void Root::toggleHDR(bool hdr){
glDeleteFramebuffers((hdr ? 2 : 1), &FBO);
glDeleteRenderbuffers(1, &RBO);
@@ -651,9 +642,9 @@ namespace vb01{
glNamedBufferSubData(objLightBuffer, 0, sizeof(LightData) * lightData.size(), lightData.data());
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, objLightBuffer);
for(int i = 0; i < currTextureDims.size(); i++){
for(int i = 0; i < meshTextureData.size(); i++){
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_2D_ARRAY, meshTextureBuffer[i]);
glBindTexture(GL_TEXTURE_2D_ARRAY, meshTextureData[i].buffer);
}
glBindVertexArray(meshVAO);
@@ -674,9 +665,9 @@ namespace vb01{
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GuiData) * guiData.size(), guiData.data(), GL_DYNAMIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, guiDataBuffer);
for(int i = 0; i < currTextureDims.size(); i++){
for(int i = 0; i < guiTextureData.size(); i++){
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_2D_ARRAY, guiTextureBuffer[i]);
glBindTexture(GL_TEXTURE_2D_ARRAY, guiTextureData[i].buffer);
}
glBindVertexArray(guiVAO);
@@ -702,6 +693,7 @@ namespace vb01{
if(!gui){
objVertData.clear();
objFragData.clear();
drawCmds.clear();
for(DrawElementsIndirectCommand &cmd : drawCmds)
cmd.instanceCount = 0;
@@ -717,74 +709,6 @@ namespace vb01{
for(int i = 0; i < currTextureDims.size(); i++)
shader->setInt(i, "textureSamplers[" + to_string(i) + "]");
/*
if(gui){} //renderGui();
else{
renderMeshes();
//renderParticles(particleEmitters);
}
vector<Node*> descendants, opaqueNodes, transparentNodes;
node->getDescendants(descendants);
for(Node *desc : descendants){
if(!desc->isVisible()) continue;
vector<Mesh*> meshes = desc->getMeshes();
if(!meshes.empty())
for(Mesh *mesh : meshes){
bool transparentMesh = (mesh->getMaterial()->isTransparent());
(transparentMesh ? transparentNodes : opaqueNodes).push_back(desc);
}
else if(!desc->getTexts().empty())
transparentNodes.push_back(desc);
else{
opaqueNodes.push_back(desc);
}
}
int numNodes = transparentNodes.size();
for(int i = 0; i < numNodes; i++){
float d1 = transparentNodes[i]->getPosition().z;
if(!gui){
Vector3 v1 = transparentNodes[i]->getPosition() - camera->getPosition();
float a1 = v1.norm().getAngleBetween(camera->getDirection());
d1 = v1.getLength() * cos(a1);
}
for(int j = i; j < numNodes; j++){
float d2 = transparentNodes[j]->getPosition().z;
if(!gui){
Vector3 v2 = transparentNodes[j]->getPosition() - camera->getPosition();
float a2 = v2.norm().getAngleBetween(camera->getDirection());
d2 = v2.getLength() * cos(a2);
}
if(d1 > d2)
swap(transparentNodes[i], transparentNodes[j]);
}
}
vector<Node*> renderNodes = opaqueNodes;
renderNodes.insert(renderNodes.end(), transparentNodes.begin(), transparentNodes.end());
for(Node *renderNode : renderNodes){
//renderNode->update();
for(Mesh *mesh : renderNode->getMeshes()){
mat->getShader()->use();
mat->getShader()->setInt(0, "textureSampler");
}
}
*/
}
void Root::updateBloomFramebuffer(){
+12 -10
View File
@@ -37,13 +37,12 @@ namespace vb01{
void start(int, int, std::string, std::string);
void toggleHDR(bool);
void toggleBloom(bool);
void addMeshes(Node*);
void createSkybox(std::string[6]);
void createSkybox(vb01::Texture*);
void removeSkybox();
void initVertexDataOnGpu(MeshData&, u32&, u32&, u32&, bool);
void initTextureDataOnGpu(int, int);
void initTextureDataOnGpu(u32*, u8*, int, int, int&);
void initTextureDataOnGpu(u8*, int, int, int&, int&, bool);
void updateRenderNodeData(Node*);
void createCubemap(bool, bool, std::string[6], int);
inline Shader* getPhongShader(){return phongShader;}
@@ -54,8 +53,6 @@ namespace vb01{
inline u32& getGuiVAO(){return guiVAO;}
inline u32& getGuiVBO(){return guiVBO;}
inline u32& getGuiEBO(){return guiEBO;}
inline u32* getMeshTextureBuffer(){return meshTextureBuffer;}
inline u32* getGuiTextureBuffer(){return guiTextureBuffer;}
inline u32* getGuiPlaneTextureBuffer(){return guiPlaneTextureBuffer;}
inline const int getMaxNumShapeKeys(){return MAX_NUM_SHAPE_KEYS;}
inline Camera* getCamera(){return camera;}
@@ -83,6 +80,9 @@ namespace vb01{
int baseVertex = 0;
u32 baseInstance = 0;
};
struct ObjectIdData{
int drawId = 0, instanceId = 0;
};
struct ObjectVertexData {
float shapeKeyFactors[24];
glm::mat4 viewProj, model, bones[256];
@@ -109,18 +109,18 @@ namespace vb01{
float diffuseColor[4];
};
struct TextureUnitGpuData {
u32 *buffer = nullptr;
u32 buffer = -1;
int numLayers = 0, width = 0, height = 0;
TextureUnitGpuData(u32 *b, int l, int w, int h) : buffer(b), numLayers(l), width(w), height(h){}
TextureUnitGpuData(int w, int h) : width(w), height(h){}
};
glm::mat4 projView;
const int MAX_NUM_SHAPE_KEYS = 5;
int NUM_MAX_TEXTURE_UNITS = 0, NUM_MAX_TEXTURE_ARRAY_SIZE = 0, numLights = 0, width, height, blurLevel = 10, currNumVerts = 0, currNumIndexes = 0, depthmapSize = 512, currNumLayers = 0;
u32 meshVAO = -1, meshVBO = -1, meshEBO = -1, *meshTextureBuffer = nullptr, *depthmapBuffer = nullptr;
u32 meshVAO = -1, meshVBO = -1, meshEBO = -1;
u32 particleVAO = -1, particleVBO = -1;
u32 guiVAO = -1, guiVBO = -1, guiEBO = -1, *guiTextureBuffer = nullptr;
u32 guiVAO = -1, guiVBO = -1, guiEBO = -1;
u32 guiPlaneVAO = -1, guiPlaneVBO = -1, guiPlaneEBO = -1, *guiPlaneTextureBuffer = nullptr;
u32 skyboxVAO = -1, skyboxVBO = -1, skyboxEBO = -1, skyboxBuffer = -1;
u32 FBO = -1, RBO = -1, pingpongBuffers[2], drawCmdBuffer = -1, objVertBuffer = -1, objFragBuffer = -1, objLightBuffer = -1, guiDataBuffer = -1;
@@ -138,12 +138,14 @@ namespace vb01{
std::vector<std::pair<int, int>> currTextureDims;
std::vector<u32> currentIndices;
std::vector<Mesh*> meshes;
std::vector<DrawElementsIndirectCommand> drawCmds;
std::vector<DrawElementsIndirectCommand> drawCmds, drawCmds2;
std::vector<ObjectIdData> objIdData;
std::vector<ObjectVertexData> objVertData;
std::vector<ObjectFragmentData> objFragData;
std::vector<LightData> lightData;
std::vector<GuiData> guiData;
std::vector<TextureUnitGpuData> textureGpuData;
std::vector<int> numObjGpuInstances;
std::vector<TextureUnitGpuData> meshTextureData, depthmapData, guiTextureData;
std::string libPath;
Root();
+3 -2
View File
@@ -45,7 +45,7 @@ namespace vb01{
if(!cm){
ImageAsset *imgAsset = (ImageAsset*)AssetManager::getSingleton()->getAsset(paths[i]);
frames.push_back(Frame(nullptr, imgAsset->layerId));
frames.push_back(Frame(imgAsset->bufferId, imgAsset->layerId));
}
}
@@ -59,7 +59,8 @@ namespace vb01{
Texture::Texture(string path, int id) : Animatable(Animatable::TEXTURE){
FontAsset *fontAsset = (FontAsset*)AssetManager::getSingleton()->getAsset(path);
frames.push_back(Frame(nullptr, fontAsset->getGlyph(id).layerId));
const FontAsset::Glyph &glyph = fontAsset->getGlyph(id);
frames.push_back(Frame(glyph.bufferId, glyph.layerId));
}
Texture::~Texture(){
+2 -3
View File
@@ -32,10 +32,9 @@ namespace vb01{
inline bool isTransparent(){return png;}
private:
struct Frame{
u32 *buffer = nullptr;
int layerId = 0;
int bufferId = 0, layerId = 0;
Frame(u32 *b, int lid) : buffer(b), layerId(lid){}
Frame(int bid, int lid) : bufferId(bid), layerId(lid){}
};
bool cubemap = false, png = false;
+2 -2
View File
@@ -208,9 +208,9 @@ namespace vb01{
numShapeKeys
);
Root *root = Root::getSingleton();
root->initVertexDataOnGpu(meshData, root->getMeshVAO(), root->getMeshVBO(), root->getMeshEBO(), true);
Mesh *mesh = new Mesh(meshData);
Root *root = Root::getSingleton();
root->initVertexDataOnGpu(mesh->getMeshBase(), root->getMeshVAO(), root->getMeshVBO(), root->getMeshEBO(), true);
return mesh;
}