既存の OpenGL アプリケーションに UI オーバーレイを追加するコードをいくつか書きました。
残念ながら、私は OpenGL に精通していませんが、一部のデバイスでは何らかの形で常に失敗することを知っています。
いくつかの裏話:
一般的なパイプラインは次のとおりです。
アプリケーション レンダリング -> UI が FBO にレンダリングされる -> FBO がブリットされて RGBA テクスチャが取得される -> テクスチャが UI シーンの上に描画されます。
ここまでは順調でしたが、Ubuntu 16.04 の Intel カードでコンテキスト スイッチ間でテクスチャが壊れる問題に遭遇しました (UI レンダリングは QOpenGLContext を使用して行われ、アプリケーションは OGRE によって管理される生の OpenGL コンテキストですが、QOpenGLContext はリソースを共有するように設定されています)。共有が機能するかどうかを確認することでその問題を解決し (1 つのコンテキストでテクスチャを作成し、別のコンテキストでコンテンツが正しいかどうかを確認します)、そうでない場合は、コンテキスト 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 です。
編集:明確でない場合は、テクスチャの元のコンテキストではなく、アプリケーションのコンテキストでテクスチャをコピーしています。これは、作業中のテクスチャが作成されるコンテキストと同じです。したがって、共有が機能しない場合は、コピーしないでください。その時点で正しいコンテンツを取得します。