Nsight unable to debug OpenGL [The following API usage is unsupported: glBindBufferBase]

Well guys, I’m trying to debug an OpenGL 4.5 Core Profile application and capture a frame, but I get this error:

The following API usage is unsupported:
glBindBufferBase (target = 0x00008892)
To see all incompatibilities, see C:\Users\Tom\Documents\NVIDIA Nsight\nvcompatlog.txt
Please send this list to devtools-support@nvidia.com

My system:
Windows 10 x64
VisualStudio 15.5.2
Nsight 5.0.0.17240
GeForce 1080Ti, driver: 388.19

Any ideas?

Hi master.of.m42,

I’m sorry for the problem you met, can we have your sample to identify the issue please?
I guess the target parameter is unsupported by nsight.

Thanks,
Letitia

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 :(

Hi master.of.m42,

Nsight 5.4 supports the OpenGL 4.5 core profile which contains the function glBindBufferBase, which can be referred to the link NVIDIA Nsight Visual Studio Edition User Guide

As far as the version for QtCreator, I am not sure about the plan or schedule, but I will take a track for your request and let you know if there are some update.

Thanks,
Letitia

Letitia, yes, please, ask the developers to make a version for QtCreator, this fu…d studio already got me with its bugs and lags …
And where will you create this thread? Give me a link please to the question to the developers…

Hi master.of.m42,

Maybe you can find the related forum in the link https://devtalk.nvidia.com/ and raise your questions.

Regards,
Letitia