Производительность OpenGL glReadPixels

Я пытаюсь внедрить автоматическую экспозицию для сопоставления тонов HDR, и я пытаюсь снизить затраты на определение средней яркости моей сцены, и я, похоже, попал в точку удушья с glReadPixels. Вот моя установка:

1: Я создаю FBO с пониженной частотой дискретизации, чтобы снизить стоимость чтения при использовании glReadPixels, используя только значения GL_RED и в формате GL_BYTE.

private void CreateDownSampleExposure() {
        DownFrameBuffer = glGenFramebuffers();
        DownTexture = GL11.glGenTextures();
        glBindFramebuffer(GL_FRAMEBUFFER, DownFrameBuffer);
        GL11.glBindTexture(GL11.GL_TEXTURE_2D, DownTexture);
        GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RED, 1600/8, 1200/8,
                0, GL11.GL_RED, GL11.GL_BYTE, (ByteBuffer) null);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                GL11.GL_TEXTURE_2D, DownTexture, 0);
        if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
            System.err.println("error");
        } else {
            System.err.println("success");
        }
        GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
        glBindFramebuffer(GL_FRAMEBUFFER, 0);

    }

2: Настройка ByteBuffers и чтение текстуры FBO текстуры Выше.

Setup(){
byte[] testByte = new byte[1600/8*1000/8];
ByteBuffer testByteBuffer = BufferUtils.createByteBuffer(testByte.length);
testByteBuffer.put(testByte);
testByteBuffer.flip();
}
MainLoop(){
  //Render scene and store result into downSampledFBO texture

   GL11.glBindTexture(GL11.GL_TEXTURE_2D, DeferredFBO.getDownTexture());

  //GL11.glGetTexImage(GL11.GL_TEXTURE_2D, 0, GL11.GL_RED, GL11.GL_BYTE,       
  //testByteBuffer); <- This is slower than readPixels. 

  GL11.glReadPixels(0, 0, DisplayManager.Width/8, DisplayManager.Height/8, 
  GL11.GL_RED, GL11.GL_BYTE, testByteBuffer);
  int x = 0;

  for(int i = 0; i <testByteBuffer.capacity(); i++){
        x+= testByteBuffer.get(i);
        }
    System.out.println(x); <-Print out accumulated value of brightness. 
    }
  //Adjust exposure depending on brightness. 

Проблема в том, что я могу уменьшить размер текстуры FBO в 100 раз, поэтому мой glReadPixels считывает только 16x10 пикселей, и прирост производительности практически отсутствует. Отсутствие понижения частоты дискретизации дает значительный прирост производительности, но как только я преодолеваю деление ширины и высоты на 8, кажется, что она падает. Кажется, что просто вызов этой функции требует огромных накладных расходов. Есть ли что-то, что я делаю неправильно или не учитываю при вызове glReadPixels?.


person user3452887    schedule 30.09.2015    source источник
comment
Судя по всему readPixels медленный и от Дарта Мелькора на GameDev Количество прочитанных пикселей не так важно, как зависание, которое вы все равно получите даже с регионом 1x1 и на самом быстром современном железе - лучше использовать метод, который не задействует чтение назад. Я полагаю, я попытаюсь найти лучший более эффективный способ. Я попробую Pixel Buffer Objects.   -  person user3452887    schedule 30.09.2015


Ответы (1)


glReadPixels работает медленно, потому что ЦП должен ждать, пока ГП завершит весь свой рендеринг, прежде чем он сможет дать вам результаты. Страшная точка синхронизации.

Один из способов сделать glReadPixels быстрым — использовать какую-то схему двойной/тройной буферизации, чтобы вы вызывали glReadPixels только для тех текстур, которые, как вы ожидаете, уже завершились графическим процессором. Это целесообразно только в том случае, если ожидание пары кадров перед получением результата glReadPixels допустимо в вашем приложении. Например, в видеоигре латентность может быть оправдана как симуляция времени реакции зрачка на изменение условий освещения.

Однако для вашего конкретного примера тональной компрессии, по-видимому, вы хотите рассчитать среднюю яркость только для того, чтобы передать эту информацию обратно в графический процессор для другого прохода рендеринга. Вместо glReadPixels вычисляйте среднее значение, последовательно копируя изображение в цели рендеринга половинного размера с линейной фильтрацией (прямоугольный фильтр), пока не достигнете цели 1x1.

Эта цель 1x1 теперь представляет собой текстуру, содержащую вашу среднюю яркость, и может использовать эту текстуру в вашем проходе рендеринга с отображением тонов. Нет точек синхронизации.

person Columbo    schedule 30.09.2015