如何在OpenGL中动态跟踪纹理单元?

3
我目前正在为我正在开发的一个项目创建纹理类,我试图从一开始就做好一切以防止未来的麻烦。
目前,我将纹理信息加载到GPU的方式如下:
void Texture::load_to_GPU(GLuint program)
{
    if(program == Rendering_Handler->shading_programs[1].programID)
        exit(EXIT_FAILURE);
    glUseProgram(program);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, textureID);

    GLint loc = glGetUniformLocation(program, "text");
    if(loc == GL_INVALID_VALUE || loc==GL_INVALID_OPERATION)
    {
        cerr << "Error returned when trying to find texture uniform."
            << "\nuniform: text"
            << "Error num: " << loc
            << endl;
        return;
    }

    glUniform1i(loc,0);
}

我希望能够动态确定纹理单元。
例如,不是硬编码统一名称“text”,而是将字符串作为参数传递,并执行类似于glGetUniformLocation()的操作,但用于纹理单元。
换句话说,我想要动态选择要绑定纹理的纹理单元,而不是硬编码它。
为此,我需要找到一个当前未使用的纹理单元,最好从最小的纹理单元到最大的纹理单元。
哪些OpenGL函数可以实现这种行为?
编辑:
我需要实现所需行为的重要工具是:
一旦将纹理单元绑定到采样器统一变量,我希望能够获取绑定到该统一变量的纹理单元。
因此,如果将纹理单元5绑定到统一变量“sampler2d texture_5”中,
我希望有一个函数,它接受统一标签并返回绑定到该标签的纹理单元。

你可以手动跟踪已占用的纹理单元。或者你可以使用 glGet(GL_TEXTURE_BINDING_2D) 来检查一个单元是否空闲。 - HolyBlackCat
最有效的方法是使用位掩码,但这需要我正确实现静态方法和变量来跟踪已占用和未占用的纹理单元。而且我打算在将来多线程化我的应用程序,所以这可能会带来很多麻烦。如果OpenGL本身可以跟踪哪些纹理单元是活动的或不活动的,那么这将简化该过程。 - Makogan
正如我所说,您可以检查一个单元是否被占用。但是循环查找空闲单元似乎不太高效。如果您想要多线程,则会遇到更多问题,因为一次只能有一个线程与GL上下文交互,并且您需要手动指定哪个线程是那个线程。此外,glGetUniformLocation在出现错误时返回-1而不是错误代码。这些代码将由glGetError()返回。 - HolyBlackCat
那并不完全正确,每个线程可能只有一个上下文,但是信息可以在多个上下文之间共享。我以前使用过多线程OpenGL,所以我知道这是非常可行的,你只需要小心处理。 - Makogan
@Makogan:“信息可以在多个上下文之间共享”。每个上下文都有独立的上下文状态。它们可以共享相同的对象,但它们不共享这些对象的上下文绑定。因此,如果您将纹理绑定到上下文0的单元0上,则对于上下文1的单元0没有影响,即使这两个上下文共享对象。 - Nicol Bolas
1个回答

1
我假设你已经封装了所有的纹理绑定/解绑操作。
如果是这样,你可以使用以下方法在O(1)时间内分配和释放纹理单元,使用O(n)内存。
(我没有在其他地方看到过这种方法,也不知道这种数据结构的名称。如果有人知道它叫什么,请告诉我。)
constexpr int capacity = 64; // A total number of units.
int size = 0; // Amount of allocated units.

std::vector<int> pool, indices;

void init()
{
    pool.resize(capacity);
    std::iota(pool.begin(), pool.end(), 0);
    indices.resize(capacity);
    std::iota(indices.begin(), indices.end(), 0);
}

int alloc()
{
    if (size >= capacity)
        return -1; // No more texture units.
    return pool[size++];
}

void free(int unit)
{
    // assert(indices[unit] < size) - if this fails, then you have a double free
    size--;
    int last_unit = pool[size];
    std::swap(pool[indices[unit]], pool[size]);
    std::swap(indices[unit], indices[last_unit]);
}

虽然我喜欢你的方法,因为它非常优雅。但我认为使用位掩码会更有效率,因为尽管您需要在位数上进行线性搜索,这是O(n)的,但由于我们处理的是非常小的数据状态(<64),而且位操作非常高效,所以位掩码方法最终具有可比较的运行时间,并且使用RAM更少。是否可以获取绑定到采样器统一变量的纹理单元? - Makogan
@Makogan glGetUniformiv() 应该可以工作。如果你最终对这两种方法进行了分析,我会很感兴趣知道结果。不知道哪个更快。 - HolyBlackCat
这个如何处理多个纹理绑定到同一个纹理单元的情况? - Nicol Bolas
@NicolBolas 我会遵循您的建议,忘记这可以做到的事情: https://dev59.com/cnPYa4cB1Zd3GeqPehFm?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa - Makogan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接