2015-06-08 3 views
0

Я пытаюсь прочитать содержимое обратного буфера в моем собственном буфере. glReadPixels сам по себе слишком медленный и снижает мой FPS от 50 до 30.Быстрый просмотр буфера чтения OpenGL

Итак, я решил попробовать «асинхронный» читать с помощью PBuffer, но он сработает.

Мой код выглядит следующим образом:

Если буферы не существует, создайте их. В противном случае, читать задний буфер в указанное место памяти:

static int readIndex = 0; 
static int writeIndex = 1; 
static GLuint pbo[2] = {0}; 


void FastCaptureBackBuffer() 
{ 
    //Create PBOs: 
    if (!initBuffers) 
    { 
     initBuffers = true; 
     glGenBuffers(2, pbo); 
     glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo[0]); 
     glBufferData(GL_PIXEL_PACK_BUFFER, width * height * 1.0f, 0, GL_STREAM_READ); 

     glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo[1]); 
     glBufferData(GL_PIXEL_PACK_BUFFER, width * height * 1.0f, 0, GL_STREAM_READ); 
     glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); 
    } 

    //swap read and write. 
    writeIndex = (writeIndex + 1) % 2; 
    readIndex = (writeIndex + 1) % 2; 

    //read back-buffer. 
    glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo[writeIndex]); 
    glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, nullptr); 
    glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo[readIndex]); 

    void* data = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY); 

    if (data) 
    { 
     memcpy(myBuffer, data, width * height * 4); 
     data = nullptr; 
     glUnmapBuffer(GL_PIXEL_PACK_BUFFER); 
    } 

    glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); 
} 

Тогда я:

BOOL __stdcall HookSwapBuffers(HDC DC) 
{ 
    FastCaptureBackBufferPBO(); 

    return CallFunction<BOOL>(GetOriginalAddress(353), DC); 
} 

Таким образом, каждый раз, когда приложение вызывает wglSwapBuffers, я прочитал назад буфер прямо, пока он не поменяны местами.

Как я могу быстро прочитать задний буфер? Что мне не хватает в приведенном выше?

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

Любой другой способ, и я в конечном итоге копирую задний буфер в блок памяти, и он медленный.

Любые идеи?

+0

Просто FYI: PBuffers - это нечто совсем иное, чем Pixel Buffer Objects. PBuffer - это особый вид выведенного из экрана экрана (вид окна, который нельзя сделать видимым). PBuffers использовались для внеэкранного рендеринга, прежде чем появились объекты Framebuffer (FBOs). – datenwolf

ответ

3

Вы не оставляя достаточно памяти в буфере:

glBufferData(GL_PIXEL_PACK_BUFFER, width * height * 1.0f, 0, GL_STREAM_READ); 

Поскольку вы используете GL_RGBA как формат, вы будете нуждаться в 4 байта на пиксель, который также соответствует тому, что вы используете в вашей memcpy() вызов:

memcpy(myBuffer, data, width * height * 4); 

Так glBufferData() вызов должен быть:

glBufferData(GL_PIXEL_PACK_BUFFER, width * height * 4, 0, GL_STREAM_READ); 

Кроме того, из вашего вопроса не совсем понятно, почему вы используете HookSwapBuffers(). Я считаю, что люди используют это, чтобы перехватить вызов SwapBuffers(), если у них нет исходного кода. Если вы хотите захватить рендеринг, вы делаете сами в своем собственном коде, вы можете просто позвонить по номеру glReadPixels() сразу же после того, как закончите рендеринг кадра. Он будет выполняться последовательно со всеми другими вызовами OpenGL, поэтому он будет содержать результат всех выписанных вызовов.

Незначительная терминологическая точка. То, о чем вы просите, здесь не называется «PBuffer». Полное имя «Pixel Buffer Object», часто используемое в его короткой форме «PBO». А PBuffer - это нечто совсем другое. Это был старый механизм внеэкранного рендеринга, который, к счастью, в наши дни в основном устарел.

0

Любые идеи?

Как насчет, не засоряйте фреймбуфер главное что-то вы не сделать (оказание оконного фреймбуфер и читать от этого), и вместо этого использовать объект Framebuffer и renderbuffer оказывать. Вам все равно придется использовать glReadPixels, но поскольку вы используете внешнюю поверхность, вы избегаете всей этой синхронизации с системой окон.Использование PBO для передачи данных по-прежнему рекомендуется, так как это дает OpenGL-реализации большую свободу в планировании операций. Я предлагаю следующее:

  1. отдавайте FBO renderbuffer
  2. glReadPixels из renderbuffer в GL_PIXEL_PACK_BUFFER ПБ
  3. блитирования в renderbuffer к главному фреймбуферу
  4. SwapBuffers
  5. извлечение данных из ПБО

Эта схема и порядок операций дают OpenGL-реализацию достаточную свободу действий для асинхронного Usly перекрывают некоторые из операций, происходящих там, не налагая некоторые точки остановки синхронизации. Например, glReadPixels и blitting renderbuffer к основному фреймбуферу не мешают друг другу (оба читаются только из renderbuffer). Драйвер OpenGL может переставить для glReadPixels, которые будут фактически выполняться после blit или в одно и то же время. Вы можете поменять местами 2 и 3, а на некоторых реализациях это может привести к повышению производительности. Черт, вы могли бы двигаться 2 даже после 4, но тогда вы потеряете некоторую операцию, переупорядочивающую свободу.