Мультисэмпловая целочисленная текстура OpenGL, прикрепленная к буферу кадра, не разрешается правильно

Итак, я использую кадровый буфер с несколькими целями рендеринга, в котором первое вложение цвета — это цветная текстура (RGBA8), а второй буфер отрисовки (вложение цвета 1) — индексная текстура (R32UI).

gl::BindTexture(gl::TEXTURE_2D_MULTISAMPLE, m_Textures[eTEXTURE_COLORBUFFER]);
gl::TexParameteri(gl::TEXTURE_2D_MULTISAMPLE, gl::TEXTURE_BASE_LEVEL, 0);
gl::TexParameteri(gl::TEXTURE_2D_MULTISAMPLE, gl::TEXTURE_MAX_LEVEL, 0);
gl::TexImage2DMultisample(gl::TEXTURE_2D_MULTISAMPLE, m_Multisample,gl::RGBA8,width,height,gl::FALSE_);

gl::BindTexture(gl::TEXTURE_2D_MULTISAMPLE, m_Textures[eTEXTURE_CLASSBUFFER]);
gl::TexParameteri(gl::TEXTURE_2D_MULTISAMPLE, gl::TEXTURE_BASE_LEVEL, 0);
gl::TexParameteri(gl::TEXTURE_2D_MULTISAMPLE, gl::TEXTURE_MAX_LEVEL, 0);
gl::TexImage2DMultisample(gl::TEXTURE_2D_MULTISAMPLE, m_Multisample,gl::R32UI,width,height,gl::FALSE_);

Обе текстуры мультисэмплированы, и я хотел бы загрузить их на процессор после завершения рендеринга. Хотя, когда я преобразовывал многовыборочный FBO в одновыборочный FBO, возвращаемые данные текстуры индекса состоят из всех нулей, в то время как цветовая текстура разрешается правильно.

// Resolve multisampling
if ( m_Multisample > 0 )
{
    gl::BindFramebuffer(gl::READ_FRAMEBUFFER, m_Framebuffers[eFBO_RENDERBUFFER]);
    gl::BindFramebuffer(gl::DRAW_FRAMEBUFFER, m_Framebuffers[eFBO_RESOLVEBUFFER]);
    gl::BlitFramebuffer(0, 0, m_FrameDims, m_FrameDims, 0, 0, m_FrameDims, m_FrameDims, 
        gl::COLOR_BUFFER_BIT, gl::NEAREST);

    gl::enum_t blit_error = gl::NO_ERROR_;
    blit_error = gl::GetError();
    if ( blit_error != gl::NO_ERROR_ )
    {
        throw framebuffer_error(string::format<128>(
            "BlitFramebuffer failed with error: %d",blit_error));
    }

    gl::BindFramebuffer(gl::READ_FRAMEBUFFER, m_Framebuffers[eFBO_RESOLVEBUFFER]);
}

Я использую флаг NEARST, потому что кажется, что целочисленные текстуры не работают с LINEAR интерполяцией.

Код, который я использую для загрузки изображения, указан здесь.

uint32_t* tex_data = new uint32_t[query.m_FrameDims*query.m_FrameDims];
memset(tex_data,0,sizeof(uint32_t)*query.m_FrameDims*query.m_FrameDims);
gl::BindTexture(gl::TEXTURE_2D,query.m_DestColorTexture);
{
    // Copy color texture
    gl::ReadBuffer(gl::COLOR_ATTACHMENT0);
    gl::ReadPixels(0,0,query.m_FrameDims,query.m_FrameDims,
        gl::RGBA,gl::UNSIGNED_BYTE,tex_data);
    gl::TexSubImage2D(gl::TEXTURE_2D,0,0,0,query.m_FrameDims,query.m_FrameDims,
        gl::RGBA,gl::UNSIGNED_BYTE,tex_data);
}

gl::BindTexture(gl::TEXTURE_2D,query.m_DestClassTexture);
{
    // Copy class texture
    gl::ReadBuffer(gl::COLOR_ATTACHMENT1);                      
    gl::ReadPixels(0,0,query.m_FrameDims,query.m_FrameDims,
            gl::RED_INTEGER,gl::UNSIGNED_INT,tex_data);
    gl::TexSubImage2D(gl::TEXTURE_2D,0,0,0,query.m_FrameDims,query.m_FrameDims,
            gl::RED_INTEGER,gl::UNSIGNED_INT,tex_data);
}

delete[] tex_data;

Если я отключу многовыборочный FBO, избегая вызова функции gl::BlitFramebuffer(), все будет работать нормально.

Я не вижу никаких документов, в которых говорится, что целочисленная текстура может быть мультисэмплирована, но даже при этом я не уверен, что они вообще имеют смысл.

Любая подсказка, где я могу ошибаться?


person 3Nu    schedule 16.09.2013    source источник
comment
Целое число + мультивыборка? Звучит не очень разумно, давайте сначала посмотрим, поддерживается ли это... Хорошо, вроде поддерживается, но что говорит GL_MAX_INTEGER_SAMPLES (поскольку оно может отличаться от GL_MAX_SAMPLES)? Это ›1?   -  person Christian Rau    schedule 16.09.2013
comment
Хм, хорошая попытка, но моя GTX 660, похоже, способна выдавать 32 максимальных целочисленных выборки :(. В любом случае спасибо.   -  person 3Nu    schedule 16.09.2013
comment
Знаете ли вы, что в коде, который вы вставили, вы копируете только одно из двух вложений цветового буфера? Смотрите мой обновленный ответ, он должен решить вашу проблему.   -  person Andon M. Coleman    schedule 18.09.2013


Ответы (1)


Вы можете считывать только из одного цветового буфера в то время, когда вы выполняете блитирование кадрового буфера; вы можете записывать во многие буферы отрисовки (технически до GL_MAX_DRAW_BUFFERS одновременно). Проблема здесь в том, что вы хотите читать из двух разных цветовых буферов и пытаетесь сделать это за один блит.

Основная спецификация OpenGL 4.4 — 18.3. Копирование пикселей - (стр. 483)

При передаче цветового буфера значения берутся из буфера чтения считанного буфера кадра и записываются в каждый из буферов отрисовки отрисовки. кадровый буфер.


Ваш код показывает мне, что вы забыли сделать второй блит для прикрепления второго цвета, и поэтому он оказывается пустым.

Чтобы исправить это, я ожидал увидеть что-то вроде:

// Resolve multisampling
if ( m_Multisample > 0 )
{
  //
  // Do the first resolve (COLOR_ATTACHMENT0)
  //
  gl::BindFramebuffer(gl::READ_FRAMEBUFFER,m_Framebuffers[eFBO_RENDERBUFFER]);
  gl::ReadBuffer     (gl::COLOR_ATTACHMENT0); // Read:  Attachment 0 (MSAA)

  gl::BindFramebuffer(gl::DRAW_FRAMEBUFFER,m_Framebuffers[eFBO_RESOLVEBUFFER]);
  gl::DrawBuffer     (gl::COLOR_ATTACHMENT0); // Write: Attachment 0 (Resolve)

  gl::BlitFramebuffer(0, 0, m_FrameDims, m_FrameDims, 0, 0, m_FrameDims,
      m_FrameDims, gl::COLOR_BUFFER_BIT, gl::NEAREST);

  gl::enum_t blit_error = gl::NO_ERROR_;
  blit_error = gl::GetError();
  if ( blit_error != gl::NO_ERROR_ )
  {
      throw framebuffer_error(string::format<128>(
          "BlitFramebuffer failed with error: %d",blit_error));
  }

  //
  // Do the second resolve (COLOR_ATTACHMENT1)
  //
  gl::BindFramebuffer(gl::READ_FRAMEBUFFER,m_Framebuffers[eFBO_RENDERBUFFER]);
  gl::ReadBuffer     (gl::COLOR_ATTACHMENT1); // Read:  Attachment 1 (MSAA)

  gl::BindFramebuffer(gl::DRAW_FRAMEBUFFER,m_Framebuffers[eFBO_RESOLVEBUFFER]);
  gl::DrawBuffer     (gl::COLOR_ATTACHMENT1); // Write: Attachment 1 (Resolve)

  gl::BlitFramebuffer(0, 0, m_FrameDims, m_FrameDims, 0, 0, m_FrameDims,
      m_FrameDims, gl::COLOR_BUFFER_BIT, gl::NEAREST);

  gl::enum_t blit_error = gl::NO_ERROR_;
  blit_error = gl::GetError();
  if ( blit_error != gl::NO_ERROR_ )
  {
      throw framebuffer_error(string::format<128>(
          "BlitFramebuffer failed with error: %d",blit_error));
  }

  gl::BindFramebuffer(gl::READ_FRAMEBUFFER,m_Framebuffers[eFBO_RESOLVEBUFFER]);
}

Это предполагает, что текстуры/буферы рендеринга, которые вы хотите использовать, имеют одну и ту же точку присоединения. Если нет, вы можете соответствующим образом настроить gl::ReadBuffer (...) и gl::DrawBuffer (...).

person Andon M. Coleman    schedule 18.09.2013
comment
@ AndomM.Coleman Это имеет смысл, хотя и не так интуитивно понятно. Я собираюсь попробовать это и дам вам знать. Спасибо! - person 3Nu; 18.09.2013
comment
@ AndomM.Coleman Действительно, это была проблема. Большое тебе спасибо! Это, вероятно, немного менее эффективно, чем решение всего одним вызовом, но, как вы подчеркнули, этот способ дает вам больше гибкости. - person 3Nu; 18.09.2013