Текстура отображается пустой, но glGetTexImage работает отлично

#c #qt #opengl #mesa #qopenglfunctions

#c #qt #opengl #mesa #qopenglфункции

Вопрос:

Я написал некоторый код, который добавляет наложение пользовательского интерфейса к существующему приложению OpenGL.
К сожалению, я не разбираюсь в OpenGL, но я знаю, что ему каким-то образом всегда удается выйти из строя на каком-то устройстве.
Немного предыстории:

Общий конвейер таков:
Рендеринг приложения -> Пользовательский интерфейс отображается в 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, amp;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 , она выглядит нормально, и если я скопирую ее обратно в текстуру, созданную в контексте приложения, она будет отображаться нормально.

Видеокарта — это Intel UHD 620 с версией Mesa 18.2.8.

Редактировать: на случай, если это было неясно, я копирую текстуру в контексте приложения, а не в исходном контексте текстуры, в том же контексте, в котором создается рабочая текстура, поэтому, если совместное использование не сработало, я не должен получать правильное содержимое в этот момент.