Скопируйте задний буфер OpenGL непосредственно в данные пикселей GDI DC

Я пишу графический интерфейс, который использует OpenGL через OpenTK и GLControl на C#, и я пытаюсь использовать грязные прямоугольники для рисования только элементов управления, которые должны быть нарисованы. Очевидно, что не стоит перерисовывать всю развернутую форму только для обновления кнопки при наведении курсора мыши.

Моей первой попыткой было использование glScissors, но это не ограничивает SwapBuffers, которые на моей платформе, я подозреваю (из-за производительности, почти полностью зависящей от размера окна), не "меняются", а делают полную копию буфер на передний буфер.

Второй попыткой был glAddSwapHintRectWIN, который теоретически ограничивал бы заменяемую (в данном случае копируемую) область SwapBuffers, но это только подсказка, и она вообще ничего не делает.

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

Похоже, что обновление всей области все еще происходит независимо от того, что я делаю.

Поэтому я пытаюсь использовать glReadPixels () и каким-то образом получить указатель для рисования непосредственно на данные пикселей hDC, полученные из CreateGraphics() элемента управления. Это возможно?

РЕДАКТИРОВАТЬ:

Я думаю, что-то не так с GLControl, почему производительность этого кода зависит от размера экрана, я не делаю подкачки или очистки, просто рисую треугольник постоянного размера на переднем буфере: проблема с драйвером, может быть?

        GL.DrawBuffer(DrawBufferMode.Front);

        Vector4 Color;
        Color = new Vector4((float)R.NextDouble(), 0, 0, 0.3F);

        GL.Begin(BeginMode.Triangles);

        GL.Color4(Color.X, Color.Y, Color.Z, Color.W);



        GL.Vertex3(50, 50, 0);
        GL.Vertex3(150F, 50F, 0F);
        GL.Vertex3(50F, 150F, 0F);

        GL.End();

        GL.Finish();

РЕДАКТИРОВАТЬ 2 Эти решения не являются жизнеспособными: рисование на текстуру и использование glGetTexImage для рисования на растровое изображение GDI, а затем рисование этого растрового изображения в окне hDC

Считывание пикселей буфера из буфера с использованием glReadPixels в растровое изображение GDI и затем рисование этого растрового изображения в окне hDC.

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

2 ответа

Прежде всего, какую платформу (GPU и ОС) вы используете? О каком спектакле идет речь?

Имейте в виду, что существует несколько ограничений при попытке объединить GDI и OpenGL на одном и том же hDC. Действительно, в большинстве случаев это отключит аппаратное ускорение и даст вам OpenGL 1.1 через средство визуализации программного обеспечения Microsoft.

Аппаратное ускорение OpenGL оптимизировано для перерисовки всего окна в каждом кадре. SwapBuffers() делает недействительным содержимое буфера, что делает грязные прямоугольники невозможными для реализации при двойной буферизации в буфере кадров по умолчанию.

Есть два решения:

  1. не звони SwapBuffers(), Задавать GL.DrawBuffer(DrawBufferMode.Front) и использовать одиночную буферизацию для обновления грязных прямоугольников. Это имеет серьезные недостатки, в том числе отключение композиции рабочего стола в Windows.
  2. не визуализировать напрямую в стандартный кадровый буфер. Вместо этого выделите и визуализируйте в объект framebuffer. Таким образом, вы можете обновить только те области FBO, которые были изменены. (Вам все равно нужно будет копировать FBO для отображения каждого кадра, поэтому это может быть или не быть выигрышем в производительности в зависимости от сложности вашего графического интерфейса.)

Редактировать:

40-60мс для одного треугольника означает, что вы не получаете никакого аппаратного ускорения. Проверьте GL.GetString(StringName.Renderer) - это дает название вашего GPU или возвращает "Microsoft GDI renderer"?

Если это последнее, то вы должны установить драйверы OpenGL с веб-сайта вашего поставщика графических процессоров. Сделайте это, и проблема с производительностью исчезнет.

После нескольких тестов с OpenTK оказалось, что в режиме с одиночной или двойной буферизацией замедление, наблюдаемое с увеличением размера элемента управления, все еще сохраняется, даже при включенных ножницах постоянного размера. Даже использование или нет GL.Clear() не влияет на замедление. (Обратите внимание, что только изменение высоты оказывает существенное влияние.)

Тестируя на одном примере, я получил те же результаты.

Выполнение той же пары тестов под Linux также дало те же результаты.

В Linux я заметил, что частота кадров меняется при переходе с одного дисплея на другой. Даже при отключенном vsync.

Следующим шагом будет проверка того, имеет ли DirectX такое же поведение. Если да, то ограничение находится на шине между дисплеем и графической картой.

РЕДАКТИРОВАТЬ: заключение:

Такое поведение приводит вас к ложному впечатлению. Рассматривайте только построение вашего интерфейса на FBO с грязными прямоугольными механизмами и визуализируйте его на четырехугольнике (лучше сделать из трех) и поменять местами как обычно, не думая, что вы можете улучшить свопинг для заданного размера окна, обрезая некоторые операции.

Другие вопросы по тегам