Letitia, thanks for response!
Well, my project is very large, but the function glBindBuffer is used only in one class, called GPUBuffer, this class is designed to facilitate the work on the creation and filling of OpenGL buffers buffers, it is still at the development stage and it is on Qt 5.10 (QOpenGLFunctions_4_5_Core *_f - just pointer to collection of OpenGL function). GPUBuffer - like std::vector, only for OpenGL.
Here is it:
#ifndef GPUBUFFER_H
#define GPUBUFFER_H
#include <QDebug>
#include <QOpenGLFunctions_4_5_Core>
#include <vector>
template <class T>
class GPUBuffer
{
public:
GPUBuffer(GLuint _bindingPoint, GLenum _target, GLenum _usage, QOpenGLFunctions_4_5_Core *_f, uint_fast64_t reserve = 100) : bindingPoint(_bindingPoint), target(_target), usage(_usage), f(_f)
{
if(!f)
qDebug() << "GPUBuffer error! QOpenGLFunctions_4_5_Core is null!";
Q_ASSERT(f);
elementSize = sizeof(T);
capacity = reserve;
f->glGenBuffers(1, &bufferId);
f->glBindBuffer(target, bufferId);
f->glBufferData(target, elementSize * capacity, nullptr, usage);
f->glBindBufferBase(target, bindingPoint, bufferId); //!!!
f->glBindBuffer(target, 0);
}
void reserve(uint_fast64_t desiredElNum)
{
if(desiredElNum < capacity)
return;
T* cpuBlock = nullptr;
if(elementsNum > 0)
{
GLvoid* p = mapBuffer();
cpuBlock = new T[elementsNum];
memcpy(cpuBlock, p, elementSize * elementsNum);
unmapBuffer();
}
f->glDeleteBuffers(1, &bufferId);
capacity = desiredElNum;
f->glGenBuffers(1, &bufferId);
f->glBindBuffer(target, bufferId);
f->glBufferData(target, elementSize * capacity, nullptr, usage);
if(cpuBlock)
{
f->glBufferSubData(target, 0, elementSize * elementsNum, cpuBlock);
delete cpuBlock;
}
f->glBindBufferBase(target, bindingPoint, bufferId); //!!!
f->glBindBuffer(target, 0);
}
void push_back(T item)
{
push_back(&item);
}
void push_back(T* item)
{
if(capacity < elementsNum + 1)
reserve(elementsNum + 1 + capacityOverhead);
f->glBindBuffer(target, bufferId);
f->glBufferSubData(target, elementSize * elementsNum++, elementSize, item);
f->glBindBuffer(target, 0);
}
void push_back_range(T* item, int size)
{
if(capacity < elementSize + size)
reserve(elementSize + size + capacityOverhead);
f->glBindBuffer(target, bufferId);
f->glBufferSubData(target, elementSize * elementsNum, elementSize * size, item);
elementsNum += size;
f->glBindBuffer(target, 0);
}
void erase(uint_fast64_t from, uint_fast64_t length)
{
if(length == 0)
return;
if(elementsNum == 0)
return;
if(from > elementsNum - 1)
return;
uint_fast64_t cuttedLength = length;
if(from + cuttedLength > elementsNum)
cuttedLength = elementsNum - from;
uint_fast64_t newLength = elementsNum - cuttedLength;
T* newBlock = new T[newLength];
GLvoid* p = mapBuffer();
T* pt = reinterpret_cast<T*>(p);
uint_fast64_t leftLen = from;
uint_fast64_t rightLen = elementsNum - (from + cuttedLength);
if(leftLen > 0)
memcpy(newBlock, pt, elementSize * leftLen);
if(rightLen > 0)
memcpy(newBlock + from, pt + (from + cuttedLength), elementSize * rightLen);
unmapBuffer();
f->glDeleteBuffers(1, &bufferId);
elementsNum = newLength;
capacity = elementsNum + capacityOverhead;
f->glGenBuffers(1, &bufferId);
f->glBindBuffer(target, bufferId);
f->glBufferData(target, elementSize * capacity, nullptr, usage);
f->glBufferSubData(target, 0, elementSize * elementsNum, newBlock);
delete newBlock;
f->glBindBufferBase(target, bindingPoint, bufferId); //!!!
f->glBindBuffer(target, 0);
}
void insert(uint_fast64_t from, T* items, uint_fast64_t length)
{
if(length == 0)
return;
if(from > elementsNum)
return;
uint_fast64_t newLength = elementsNum + length;
T* newBlock = new T[newLength];
if(elementsNum > 0)
{
GLvoid* p = mapBuffer();
T* pt = reinterpret_cast<T*>(p);
uint_fast64_t leftLen = from;
uint_fast64_t rightLen = elementsNum - from;
if(leftLen > 0)
memcpy(newBlock, pt, elementSize * leftLen);
if(rightLen > 0)
memcpy(newBlock + (from + length), pt + from, elementSize * rightLen);
unmapBuffer();
}
memcpy(newBlock + from, items, length);
f->glDeleteBuffers(1, &bufferId);
elementsNum = newLength;
capacity = elementsNum + capacityOverhead;
f->glGenBuffers(1, &bufferId);
f->glBindBuffer(target, bufferId);
f->glBufferData(target, elementSize * capacity, nullptr, usage);
f->glBufferSubData(target, 0, elementSize * elementsNum, newBlock);
delete newBlock;
f->glBindBufferBase(target, bindingPoint, bufferId); //!!!
f->glBindBuffer(target, 0);
}
void bind()
{
f->glBindBuffer(target, bufferId);
}
void unbind()
{
f->glBindBuffer(target, 0);
}
void bindBufferBase()
{
f->glBindBuffer(target, bufferId);
f->glBindBufferBase(target, bindingPoint, bufferId);
f->glBindBuffer(target, 0);
}
void reserveFromEnd(uint_fast64_t desiredSizeFromEnd)
{
if(capacity < elementsNum + desiredSizeFromEnd)
reserve(elementsNum + desiredSizeFromEnd + capacityOverhead);
}
bool empty()
{
return elementsNum > 0 ? false : true;
}
GLvoid* mapBuffer(GLenum access = GL_READ_ONLY)
{
f->glBindBuffer(target, bufferId);
GLvoid* p = f->glMapBuffer(target, access);
Q_ASSERT(p);
return p;
}
void unmapBuffer(bool forceUnbind = true)
{
f->glUnmapBuffer(target);
if(forceUnbind)
unbind();
}
T readElement(uint_fast64_t id)
{
T t;
if(id > elementsNum - 1)
return t;
f->glBindBuffer(target, bufferId);
GLvoid* p = f->glMapBufferRange(target, elementSize * id, elementSize, GL_MAP_READ_BIT);
if(p)
memcpy(&t, p, elementSize);
f->glUnmapBuffer(target);
f->glBindBuffer(target, 0);
return t;
}
void writeElement(uint_fast64_t id, T t)
{
f->glBindBuffer(target, bufferId);
f->glBufferSubData(target, elementSize * id, elementSize, &t);
f->glBindBuffer(target, 0);
}
uint_fast64_t getElementsNum()
{
return elementsNum;
}
GLuint getBufferId()
{
return bufferId;
}
private:
QOpenGLFunctions_4_5_Core* f = nullptr;
GLuint bufferId;
GLuint bindingPoint;
GLenum usage;
GLenum target;
uint_fast64_t elementSize = 0;
uint_fast64_t elementsNum = 0;
uint_fast64_t capacity = 0;
uint_fast64_t capacityOverhead = 50;
};
#endif // GPUBUFFER_H
Example of usage:
Decalration:
GPUBuffer<QMatrix4x4>* ssbo_model_matrices = nullptr;
Initialization:
ssbo_model_matrices = new GPUBuffer<QMatrix4x4>(0, GL_SHADER_STORAGE_BUFFER, GL_STATIC_DRAW, f);
ssbo_model_matrices ->reserve(desired_size);
for(int i - 0; i < desired_size; i++)
ssbo_model_matrices.push_back(QMatrix());
Usage in render function, just add one line before draw call:
ssbo_screen_info->bindBufferBase();
Well, i think, glBindBufferBase is not supported by Nsight, and it’s very very stange…
And Letitia, about “I guess the target parameter is unsupported by nsight”… My target platform vesion is 10.0.16299.0 (windows 10 sdk) and platform toolset VisualStudio 2015 v140 (on VisualStudio 2017) because Nsight also doesn’t work with CUDA, which is also involved in this project, on latest version of Visual Studio 2017 :-D What a hell! :-)
Dear developers of Nsight, well, finally make a version for QtCreator… VisualStudio is very problematic IDE :(