我编写了一些代码,将 UI 覆盖添加到现有的 OpenGL 应用程序中。
不幸的是,我不精通 OpenGL,但我知道它总是在某些设备上失败。
一些背景故事:
一般管道是:
应用程序渲染 -> UI 渲染到 FBO -> FBO 被 blitted 以获得 RGBA 纹理 -> 在 UI 场景之上绘制纹理。
到目前为止一切顺利,然后我在 Ubuntu 16.04 上的 Intel 卡上遇到了一个问题,其中纹理在上下文切换之间中断(UI 渲染是使用 QOpenGLContext 完成的,应用程序是由 OGRE 管理的原始 OpenGL 上下文,但 QOpenGLContext 设置为共享资源)。我通过检查共享是否有效(在一个上下文中创建纹理并检查另一个上下文中的内容是否正确)解决了这个问题,如果不是,我在上下文 B 中加载内容并在上下文 A 中再次上传。但是,由于某种原因,在同一台机器上的 Ubuntu 18.04 上,这实际上可以工作。使用 检索其内容时,纹理在其他上下文中仍然正确glGetTexImage
。
现在问题来了:它没有被渲染。我得到的只是应用程序场景,顶部没有任何东西,但是如果我手动启用下载它并重新上传到在应用程序上下文中创建的纹理的解决方法,它就可以工作。
纹理的内容怎么可能没有问题,但除非我使用抓取它glGetTexImage
并将其重新上传到在其他上下文中创建的纹理,否则它不会显示glTexImage2D
?
使用 glTexImage2D 时,一定有一些无效的状态并且设置正确。
下面是 UI 渲染后的代码:
if (!checked_can_share_texture_)
{
qopengl_wrapper_->drawInvisibleTestOverlay();
}
qopengl_wrapper_->finishRender();
if ( !can_share_texture_ || !checked_can_share_texture_ )
{
glBindTexture( GL_TEXTURE_2D, qopengl_wrapper_->texture());
glGetTexImage( GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixel_data_ );
}
glBindTexture( GL_TEXTURE_2D, 0 );
qopengl_wrapper_->doneCurrent(); // Makes the applications context current again
glDisable( GL_DEPTH_TEST );
glDisable( GL_CULL_FACE );
glDisable( GL_LIGHTING );
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glUseProgram(shader_program_);
glUniform1i(glGetUniformLocation(shader_program_, "tex"), 0);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object_);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), nullptr);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glActiveTexture( GL_TEXTURE0 );
glEnable( GL_TEXTURE_2D );
if ( can_share_texture_ )
{
glBindTexture( GL_TEXTURE_2D, qopengl_wrapper_->texture());
if ( !checked_can_share_texture_)
{
const int count = qopengl_wrapper_->size().width() * qopengl_wrapper_->size().height() * 4;
const int thresh = std::ceil(count / 100.f);
unsigned char content[count];
glGetTexImage( GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, content);
int wrong = 0;
// can_share_texture_ = false; // Bypassing the actual check will make it work
for (int i = 0; i < count; ++i) {
if (content[i] == pixel_data_[i]) continue;
if (++wrong < thresh) continue;
can_share_texture_ = false;
LOG(
"OverlayManager: Looks like texture sharing isn't working on your system. Falling back to texture copying." );
// If we can't share textures, we have to generate one
glActiveTexture( GL_TEXTURE0 );
glGenTextures( 1, &texture_ );
glBindTexture( GL_TEXTURE_2D, texture_ );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
break;
}
if (can_share_texture_)
{
delete pixel_data_;
pixel_data_ = nullptr;
LOG("Texture sharing seems supported. Count: %d", count);
}
checked_can_share_texture_ = true;
}
}
else
{
glBindTexture( GL_TEXTURE_2D, texture_ );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, qopengl_wrapper_->size().width(), qopengl_wrapper_->size().height(), 0,
GL_RGBA, GL_UNSIGNED_BYTE, pixel_data_ );
}
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glUseProgram(0);
顶点着色器
#version 130
in vec3 pos;
in vec2 coord;
out vec2 texCoord;
void main()
{
gl_Position = vec4(pos, 1.0); //Just output the incoming vertex
texCoord = coord;
}
片段着色器
#version 130
uniform sampler2D tex;
in vec2 texCoord;
void main()
{
gl_FragColor = texture(tex, texCoord);
}
TL;DR 纹理未渲染(完全透明),但如果我使用glGetTexImage
它将其复制到内存中看起来很好,并且如果我将其复制回在应用程序上下文中创建的纹理,它将渲染得很好。
显卡是带有 Mesa 版本 18.2.8 的 Intel UHD 620。
编辑:如果不清楚,我在应用程序的上下文中复制纹理而不是纹理的原始上下文,与创建工作纹理的上下文相同,所以,如果共享不起作用,我不应该在那个时候得到正确的内容。