0

我正在尝试解决运行此示例时遇到的错误。

它关于查询遮挡,本质上它渲染四次正方形改变每次视口但只有中央两次它会实际渲染一些东西,因为第一个和最后一个视口故意在监视器区域之外。

    viewports[0] = new Vec4(windowSize.x * -0.5f, windowSize.y * -0.5f, windowSize.x * 0.5f, windowSize.y * 0.5f);
    viewports[1] = new Vec4(0, 0, windowSize.x * 0.5f, windowSize.y * 0.5f);
    viewports[2] = new Vec4(windowSize.x * 0.5f, windowSize.y * 0.5f, windowSize.x * 0.5f, windowSize.y * 0.5f);
    viewports[3] = new Vec4(windowSize.x * 1.0f, windowSize.y * 1.0f, windowSize.x * 0.5f, windowSize.y * 0.5f);

每次,它将glBeginQuery使用不同的查询并第一次呈现,然后我查询GL_ANY_SAMPLES_PASSED

    // Samples count query
    for (int i = 0; i < viewports.length; ++i) {

        gl4.glViewportArrayv(0, 1, viewports[i].toFA_(), 0);

        gl4.glBeginQuery(GL_ANY_SAMPLES_PASSED, queryName.get(i));
        {
            gl4.glDrawArraysInstanced(GL_TRIANGLES, 0, vertexCount, 1);
        }
        gl4.glEndQuery(GL_ANY_SAMPLES_PASSED);
    }

然后我尝试阅读结果

    gl4.glBindBuffer(GL_QUERY_BUFFER, bufferName.get(Buffer.QUERY));
    IntBuffer params = GLBuffers.newDirectIntBuffer(1);
    for (int i = 0; i < viewports.length; ++i) {
        params.put(0, i);
        gl4.glGetQueryObjectuiv(queryName.get(i), GL_QUERY_RESULT, params);
    }

但我得到:

GlDebugOutput.messageSent(): GLDebugEvent[ id 0x502
    type Error
    severity High: dangerous undefined behavior
    source GL API
    msg GL_INVALID_OPERATION error generated. Bound query buffer is not large enough to store result.
    when 1455696348371
    source 4.5 (Core profile, arb, debug, compat[ES2, ES3, ES31, ES32], FBO, hardware) - 4.5.0 NVIDIA 356.39 - hash 0x238337ea]

如果我查看api 文档,他们会说:

params

    If a buffer is bound to the GL_QUERY_RESULT_BUFFER target, then params is treated as an offset to a location within that buffer's data store to receive the result of the query. If no buffer is bound to GL_QUERY_RESULT_BUFFER, then params is treated as an address in client memory of a variable to receive the resulting data. 

我想那句话有一个错误,我认为他们的意思是GL_QUERY_BUFFER代替GL_QUERY_RESULT_BUFFER,实际上他们GL_QUERY_BUFFER也在这里使用了例如..无论如何,如果那里绑定了任何东西,那么 params 被解释为偏移量,好的

但我的缓冲区足够大:

    gl4.glBindBuffer(GL_QUERY_BUFFER, bufferName.get(Buffer.QUERY));
    gl4.glBufferData(GL_QUERY_BUFFER, Integer.BYTES * queryName.capacity(), null, GL_DYNAMIC_COPY);
    gl4.glBindBuffer(GL_QUERY_BUFFER, 0);

所以有什么问题?

我尝试为缓冲区大小写一个大数字,例如 500,但没有成功...

我猜错误出在其他地方..你能看到吗?

4

1 回答 1

2

如果我必须回答,我说我希望如果我将缓冲区绑定到 GL_QUERY_BUFFER 目标,那么 OpenGL 应该读取参数和解释器中的值,作为它应该保存查询结果的偏移量(以字节为单位)。

不,这不是它的工作原理。

在 C/C++ 中,取值glGetQueryObject是一个指针,通常是一个指向客户端内存缓冲区的指针。对于这个特定的函数,这通常是一个堆栈变量:

GLuint val;
glGetQueryObjectuiv(obj, GL_QUERY_RESULT, &val);

val由客户端代码声明(即:调用 OpenGL 的代码)。此代码传递一个指向该变量的指针,glGetQueryObjectuiv并将数据写入该指针。

这是通过使用*Buffer类型在 C# 绑定中模拟的。这些表示连续的值数组,C# 可以从中提取与 C 和 C++ 指向数组的指针兼容的指针。

但是,当缓冲区绑定到 时GL_QUERY_BUFFER,参数的含义会发生变化。正如您所指出的,它从一个指向内存的客户端指针变成了一个偏移量。但请注意上面所说的。它没有说“指向偏移量的客户端指针”。

也就是说,指针值本身不再是指向实际内存的指针。相反,指针的数值被视为偏移量。

在 C++ 术语中,就是这样:

glBindBuffer(GL_QUERY_BUFFER, buff);
glGetQueryObjectuiv(obj, GL_QUERY_RESULT, reinterpret_cast<void*>(16));

请注意它是如何使用 16 个字节的偏移量并假装这个值实际上是一个void*谁的数值是 16。这就是重新解释强制转换所做的。

你如何在 C# 中做到这一点?我不知道; 这取决于您使用的绑定,而您从未指定它是什么。Tao 早就死了,OpenTK 看起来也正朝着那个方向发展。但我确实在 OpenTK 中找到了如何做到这一点

你需要做的是:

gl4.glBindBuffer(GL_QUERY_BUFFER, bufferName.get(Buffer.QUERY));
for (int i = 0; i < viewports.length; ++i)
{
    gl4.glGetQueryObjectuiv(queryName.get(i), GL_QUERY_RESULT,
        (IntPtr)(i * Integer.BYTES));
}

您乘以时间Integer.BYTES是因为该值是缓冲区中的字节偏移量,而不是整数数组中的整数索引。

于 2016-02-17T16:19:21.180 回答