Поддержка частичных обновлений в OpenGL ES

#3d #opengl-es

Вопрос:

Я пишу простое приложение для создания композитов (для Android), которое должно поддерживать частичные обновления. В Windows мы могли бы использовать IDXGISwapChain1::Present1 для достижения того же самого, потому что для обновления в DXGI_PRESENT_PARAMETERS требуются грязные строки.

Однако у меня возникают проблемы с поиском эквивалентного API в OpenGL-ES. В моей попытке найти эквивалентные API я обнаружил KHR_swap_buffers_with_damage и KHR_partial_update, однако они не дают мне ожидаемого результата в моем сценарии.

Мой сценарий заключается в том, что:

  1. Четкий фон с входным цветом, например — синий
  2. Нарисуйте прямоугольник входного размера и цвета с помощью частичного обновления. При частичном обновлении синий фон не должен исчезать, в то время как при полном обновлении (например, eglSwapBuffers) фон исчезнет.

Оба вышеперечисленных API заставляют фон исчезать, что кажется мне полным обновлением, несмотря на то, что я прошел грязные ректы. Я также убедился, что оба API вернули EGL_True и не имели ошибок.

Я добился некоторого успеха с использованием eglSurfaceAttrib и установил поведение EGL_SWAP_BEHAVIOR в EGL_BUFFER_PRESERVED и вызвал eglSwapBuffers. Но это больше похоже на взлом того, что я хочу.

Может ли кто-нибудь указать мне правильное направление, как я могу поддерживать частичные обновления для моего случая?

ИЗМЕНИТЬ: Немного кода, чтобы показать, как я использую API:

 if( eglSurfaceAttrib == nullptr ) // Get the function. Function pointers have same name as the function itself for clarity.
{
    //typedef bool( *demo1 ) ( EGLDisplay dpy, EGLSurface surface, EGLint rects, EGLint n_rects );
    eglSurfaceAttrib = ( demo1 )eglGetProcAddress("eglSurfaceAttrib");
}

if( done == false ) // Set surface property to EGL_BUFFER_DESTROYED
{
    eglSurfaceAttrib(display, window, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED );
    done = true;
}

EGLint val;
eglQuerySurface(display, window, EGL_BUFFER_AGE_KHR, amp;val );

if( eglSetDamageRegionKHR == nullptr )
{
    // rect and numRect are parameters to this function.
    // typedef bool( *demo ) ( EGLDisplay dpy, EGLSurface surface, const EGLint *rects, EGLint n_rects );
    eglSetDamageRegionKHR = ( demo )eglGetProcAddress( "eglSetDamageRegionKHR" );
}

eglSetDamageRegionKHR ( display, window, rects, numRect );

// Do rendering needed to get N'th frame from (N-2)nd frame (i.e. (N-age)'th frame)
// Throw error if eglSetDamageRegionKHR failed and return the error.

if( eglSwapBuffersWithDamageKHR == nullptr )
    eglSwapBuffersWithDamageKHR = ( demo )eglGetProcAddress("eglSwapBuffersWithDamageKHR");
    
eglSwapBuffersWithDamageKHR ( display, window, rects, numRect );
 

Я передаю одну прямую кишку со значением ( 0, 0, 600, 600 ) [как ( x, y, ширина, высота )] с (0,0) в левом нижнем углу экрана и осью Y, идущей вверх. Все обновления ограничены только этим регионом.

Комментарии:

1. Вы учитываете конвейерную обработку ( EGL_BUFFER_AGE_KHR ) оконных поверхностей? Помните, что когда вы выполняете частичный рендеринг без сохранения, вы не выполняете рендеринг поверх содержимого кадра N-1, вы, вероятно, выполняете рендеринг поверх кадра N-2 или N-3.

2. @solidpixel нет, я этого не учел. Это требовалось только для обновления, но я не был уверен, как его использовать, поэтому запрошенное значение осталось неиспользованным. Как бы вы посоветовали мне его использовать? Нужно ли это даже тогда, когда используется только hr_swap_buffers_with_damage?

3. Прочитайте «Пример повреждения буфера (EGL_KHR_partial_update)» части расширения KHR_partial_update.

4. TLDR: Ваши частичные обновления должны учитывать возраст буфера, потому что это определяет, что вы на самом деле визуализируете поверх.

5. @Vijju123 если solidpixel ответил на ваш вопрос, пожалуйста, поделитесь в качестве ответа самим себе окончательным решением. Если это не решено, я задаюсь вопросом, есть ли другие теги, которые вы можете добавить к этому вопросу, чтобы привлечь к нему больше внимания. В общем, всегда полезно публиковать строки кода (копировать и вставлять текст, а не изображение), чтобы люди могли помочь.

Ответ №1:

В конечном счете я решил придерживаться использования EGL_BUFFER_PRESERVE, потому что я не смог добиться каких-либо улучшений в использовании API eglSetSurfaceDamage и eglSwapBuffersWithDamage. Я также не смог найти ни малейшего намека на то, почему это было так.

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