Я написал некоторый код, который добавляет оверлей UI к существующему приложению OpenGL.
К сожалению, я не очень разбираюсь в OpenGL, но я знаю, что на каком-то устройстве ему всегда удается сбой.
Некоторыеbackstory:
Общий конвейер таков:
Визуализация приложения -> Интерфейс визуализируется в FBO -> FBO скрывается для получения текстуры RGBA -> Текстура рисуется поверх сцены пользовательского интерфейса.
Пока все хорошо, тогда я столкнулся с проблемой на картах Intel в Ubuntu 16.04, когда текстура разрывалась между переключениями контекста (рендеринг пользовательского интерфейса выполняется с использованием QOpenGLContext, приложение представляет собой необработанный контекст OpenGL, управляемый OGRE, но QOpenGLContext являетсяустановить для совместного использования ресурсов).Я решил эту проблему, проверив, работает ли совместное использование (создайте текстуру в одном контексте и проверьте, правильно ли содержимое в другом), а если нет, я загружаю контент, находясь в контексте B, и снова загружаю его в контекст A. Однако,в Ubuntu 18.04 на той же машине по какой-то причине это будет работать.Текстура все еще корректна в другом контексте при получении ее содержимого с помощью glGetTexImage
.
Теперь вот проблема: она не визуализируется.Я получаю только сцену приложения без чего-либо сверху, но если я вручную включаю обходной путь его загрузки и повторной загрузки в текстуру, которая была создана в контексте приложения, это работает.
Как может получиться, что содержимое текстуры в порядке, ноон не будет отображаться, пока я не возьму его с помощью glGetTexImage
и повторно загрузлю его в текстуру, созданную в другом контексте с помощью glTexImage2D
?
Должно быть какое-то состояние, которое недопустимо и установлено правильно при использовании glTexImage2D.
Вот код после визуализации интерфейса:
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 Texture isnне отображается (полностью прозрачно), но если я скопирую его в память, используя glGetTexImage
, он выглядит хорошо, и если я скопирую его обратно в текстуру, созданную в контексте приложения, он будет отображаться нормально.
Графическая картаIntel UHD 620 с Mesa версии 18.2.8.
Редактировать: На случай, если неясно, я копирую текстуру в контексте приложения, а неисходный контекст текстуры, тот же контекст, в котором создается рабочая текстура, поэтому, если совместное использование не сработало, я не должен получить правильное содержимое в этот момент.