OpenGL 2.0+ под Android



Реп: (119)
Для чего эта тема?
У многих создалась иллюзия сложности изучения "OpenGL", и не понимания простоты работы этой библиотеки для программиста.
И даже используя "движок" нужно понимать как это взаимодействует с ОС, что может/не может конкретные устройства.

В данной статье постараюсь выйти за рамки стандартных примеров - а именно постараюсь рассказать почему и за чем.
( тем более я давно это пообещал )
От читателей требуется хотя бы поверхностное знание любого ЯП.

Исправления приветствуются.

Все дальнейшее посвящено библиотеке OpenGL ES 2.0 под Android, и последующим версиям.

Описание OpenGL
Введение.
Что такое библиотека OpenGL ES 2.0?
На базовом уровне, OpenGL ES 2.0 — это просто спецификация, то есть документ, описывающий набор функций и их точное поведение. Производители оборудования на основе этой спецификации создают реализации — библиотеки функций, соответствующих набору функций спецификации ( W: ).

OpenGL ориентируется на следующие две задачи:
Скрыть сложности адаптации различных 3D-ускорителей, и предоставить разработчику единый API.

Для программиста OpenGL представляет низкоуровневую библиотеку для доступа к GPU ( графическому процессору ).

Схема вариантов реализации библиотеки ( с точки зрения программиста + для сравнения DirectX ):
Прикрепленное изображение

В Android на 99.99% используется вариант В.
То есть реализация OpenGL ES входит в состав драйвера,
в отличие от DirectX, которая скорее является прослойкой между приложением и драйвером.
Есть еще отдельные реализации OpenGL, например Mesa3D, но они в основном достаточно медленно развиваются и часто отстают на несколько поколений от решений производителей чипов.

Что лучше, DirectX или OpenGL?
Вопрос не корректный. Например если нужна мультиплатформенность — про DirectX можно забыть.
И на взгляд автора DirectX слишком «оброс» хвостами... ( но это очень субъективно )
+ Сравнивать не совсем корректно, так как DirectX кроме графики реализует много интерфейсов ( и вполне кошерных - включая звук, ввод, сеть и т. д. )

Что быстрее, DirectX или OpenGL?

Тоже не корректный вопрос, все зависит от опытности программиста.
Но опять на взгляд автора ( меня =) ) нестандартные возможности проще реализовывать на современных версиях OpenGL и тем более
для этого не требуются переходы на новые операционные системы ( в отличие от DirectX 10 ).
Времени на изучение тоже требуется на порядок меньше. + переносимость.

Теперь чуть-чуть про GPU:
В данный момент ( декабрь 2012г. ) в Android устройствах присутствуют два поколения GPU, Поддерживающие OpenGL ES 2.0 ( почти 95% ) и поддерживающие только версии 1.0 и 1.1.
Аппаратной обратной совместимости НЕТ.
Поэтому рассматривать версию стандарта меньше 2.0 на взгляд автора кроме как археологам не имеет смысла.
( стандарт версии 3.0 обратно совместим с 2.0 )

Структура конвейера OpenGL 1.x:
Прикрепленное изображение


Структура конвейера OpenGL 2.x+:
Прикрепленное изображение


То есть часть блоков с «железной логикой» заменили на программируемые процессоры.
Вопрос: а для чего?

А все дело в том что аппаратно было реализовано достаточно мало функций, из-за этого создавались существенные ограничения в дальнейшем развитии и гибкость была равна нулю.
История ( немного ):
Первые попытки перенести расчеты с Cpu ( центрального процессора ) были реализованы в первом Geforce ( а не в Voodoo, как думают многие ), называлать технология T&L.
Она позволяла аппаратно просчитывать на GPU освещение и выполнять уже простейшие шейдеры.
Получилось «быстро», но не осталось даже минимальной гибкости. Есть аппаратно-реализованный метод освещения например,используем. Нет — и не будет.
Следующая веха - GeForce 3, который обладал уже вполне программируемой логикой, но процессорные блоки еще небыли универсальными.
То есть блоки делились на обрабатывающие вершины и фрагментные ( обрабатывающие пиксели ).
Одни могли быть перегружены, другие простаивали...
В чем смысл наращивания процессоров ( вычислительных блоков ) у GPU?
Все дело в том что графические просчеты почти линейно маштабируется, то есть увеличение процессоров например со 100 до 200 дает почти 100% прирост производительности, так как в компьютерной графике текущий расчет обычно не зависит от предыдущего — то есть легко запаралелить.
Но и существуют некоторые ограничения, о которых будет написано ниже.
Теперь про сам OpenGL ES:

Что может OpenGL ES?
Основным принципом работы OpenGL является получение наборов векторных графических примитивов в виде точек, линий и многоугольников с последующей математической обработкой полученных данных и построением растровой картинки на экране и/или в памяти. Векторные трансформации и растеризация выполняются графическим конвейером (graphics pipeline), который по сути представляет собой дискретный автомат. Абсолютное большинство команд OpenGL попадают в одну из двух групп: либо они добавляют графические примитивы на вход в конвейер, либо конфигурируют конвейер на различное исполнение трансформаций.
Ключевая особенность — CPU и GPU работают не синхронно, то есть CPU не дожидается окончания исполнения команд от GPU, а продолжает работать ( если не было дополнительных указаний ).
Есть стек команд ( инструкций ) OpenGL.
( стек бывает двух типов, fifo и lifo. FIFO — акроним «First In, First Out» (англ. ). Принцип «первым пришёл — первым ушёл», LIFO — акроним «Last In, First Out» (англ.), обозначающий принцип «последним пришёл — первым ушёл». В OpenGL используется fifo ( очередь )).

Урок первый END.
OpenGL по своему принципу является конечным автоматом.
Что это значит?

Представьте себе конвейер производства дед.мороза =)

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

Это и есть машина конечных состояний. Проще объяснить не могу. Кто не понял - тут

Продолжение как чуть высплюсь...
( следующая тема - что скрывается за GLSurfaceView, чем это плохо и что такое EGL. )
OpenGL 2.0+ под Android (Пост Leopotam #18544726)
Что скрывается за GLSurfaceView или библиотека EGL. Подробный разбор инициализации OpenGL ES.
GLSurfaceView. улучшенный каркас приложения с использованием GLSurfaceView.
Про движки, оптимизацию и общие правила. + конкретно про java под Android.
Примитивы OpenGL Es 2.0. Матрицы,вектора и преобразования в OpenGL. Система координат под Android.
Текстуры в OpenGL ES 2.0.
Шейдеры в OpenGL ES 2.0 и язык GLSL.
Системы частиц. Билборды. Точечные спрайты.

Все статьи в PDF, благодаря who-e, Прикрепленный файлoges2.zip ( 2.76 МБ )
. Надеюсь будет полезно. Спасибо who-e.


В теме нет куратора. Если в теме есть пользователь, желающий стать Куратором и соответствующий Требованиям для кандидатов, он может подать заявку в теме Хочу стать куратором (предварительно изучив шапку темы и все материалы для кураторов).
До назначения куратора, по вопросам наполнения шапки, обращайтесь к модераторам раздела через кнопку Изображение под сообщениями, на которые необходимо добавить ссылки.


Сообщение отредактировал vaalf - 23.11.17, 12:12



Реп: (207)
Неплохо было бы еще на пальцах объяснить, что такое конечный автомат (более правильное название, а не дискретный) и что нужно сохранять / восстанавливать изменения состояния автомата, т.к. он един для всего приложения и смена флагов в одном месте может повлечь забавные глюки в другом.

Сообщение отредактировал Leopotam - 10.01.13, 22:58



Реп: (119)
Теперь пример простейшей инициализации OpenGL ES 2.0 под Android ( из премеров Google, абсолютно корявый и не применимый в реальной жизни =) ):

В приложении, методе OnCreate:

super.onCreate(savedInstanceState);

requestWindowFeature(Window.FEATURE_NO_TITLE); // Убираем заголовок
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN); // Устанавливаем полноэкранный режим

try{ // пытаемся инициализировать OpenGL
glSurfaceView = new GLSurfaceView(this);

// Далее устанавливаем версию OpenGL ES, равную 2
glSurfaceView.setEGLContextClientVersion(2);

renderer = new nRender();

glSurfaceView.setRenderer(renderer); // устанавливаем нашу реализацию GLSurfaceView.Renderer для обработки событий

glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY); // режим смены кадров
// RENDERMODE_CONTINUOUSLY - автоматическая смена кадров,
// RENDERMODE_WHEN_DIRTY - по требованию ( glSurfaceView.requestRender(); )

setContentView(glSurfaceView);

}catch(RuntimeException e){} // выводим окошко "увы, выше устройство слишком..."


,

далее создаем класс nRender

package com.example.ogl1;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import java.util.Random;

public class nRender implements GLSurfaceView.Renderer
{
public nRender() {
}

public void onDrawFrame(GL10 glUnused) { // Отрисовка кадра

Random rnd = new Random();

// Задаем случайный цвет и сводим с ума эпилептиков =)
// Цвет задается в формате RGBA, от 0.0f до 1.0f.
GLES20.glClearColor(((float)rnd.nextInt(2)/2.0f), ((float)rnd.nextInt(2)/2.0f), ((float)rnd.nextInt(2)/2.0f), 1.0f);

GLES20.glClear( GLES20.GL_COLOR_BUFFER_BIT ); // Очищаем буффер цвета
}

public void onSurfaceChanged(GL10 glUnused, int width, int height) { // изменение поверхности, например изменение размера

GLES20.glViewport(0, 0, width, height);
// Устанавливаем положение и размер вьюпорта
// вьюпорт устанавливаеться относительно поверхности ( OpenGLSurface ), в данном случае на весь экран.
// замечу, что GLES20.glClear очищает всю поверхность, все зависимости от установки Viewport.
}

public void onSurfaceCreated(GL10 glUnused, EGLConfig config) { // вызываеться при создании поверхности

}
}


Далее пробуем запустить, и получаем мечту эпилептика...

Данный пример каноничен ( по документации ), но убог и уродлив по всем проявлениям....

Сообщение отредактировал usnavii - 17.01.13, 11:55



Реп: (119)
OpenGL по своему принципу является конечным автоматом.


Что это значит?

Представьте себе конвейер производства дед.мороза =)

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

Это и есть машина конечных состояний. Проще объяснить не могу. Кто не понял - тут

Продолжение как чуть высплюсь...
( следующая тема - что скрывается за GLSurfaceView, чем это плохо и что такое EGL. )

Сообщение отредактировал usnavii - 10.01.13, 23:26



Реп: (207)
Конечный автомат - это система, содержащая в себе несколько состояний, причем можно четко определить, в каком из них она находится. Это если по-умному и непонятному.
Если ближе к отображению графики, например, выводу модели Деда Мороза на экран:
*) существует единая лента-конвейер по выводу изображения на экран, на вход которого подаются модели Деда Мороза, а на выходе получаем 2d картинку, готовую для отображения на мониторе. Конвейер выполняет обработку данных последовательно, без пропусков. Модели представляют собой набор вершин и треугольные грани (см. P.S.1), связывающие 3 соседние вершины.
*) У главного пульта конвейера есть всего, допустим, 5 тумблеров-переключателей (P.S.2), каждый из которых может находиться в состоянии вкл / выкл (см P.S.3):
-) тумблер "отрисовывать сглаженно или с острыми кромками".
-) тумблер "отрисовывать с текстурой или просто сплошным цветом". Под этим тумблером есть фото-рамка для вставки желаемой текстуры.
-) тумблер "отрисовывать все грани или только лицевые" (например, для прозрачных объектов).
-) тумблер "очищать только буфер глубины или буфер глубины и буфер цвета (изображения)".
-) еще какой-то, с красной кнопкой.
*) Стартовые значения переключателей на пульте устанавливаются в момент инициализации OpenGL и сохраняются в специальной области, называемой контекстом. Да, OpenGL может в одном приложении выводить изображение в 2 окна, каждый из которых будет иметь свой независимый контекст и свой независимый конвейер.
*) Конвейер работает все время существования окна приложения, используя для отрисовки Дедов Морозов текущие настройки на пульте. Нет необходимости перед каждой отрисовкой повторно устанавливать выключатели в старое положение.
*) Эльфы, сидящие внутри блока обработки входящей информации через конвейер, не сразу выдают результат на экран, а только после выполнения нужных операций по растеризации-отрисовке внутри себя, распараллеливая между собой. Чем совершеннее графический процессор, тем больше эльфов, способных работать параллельно для отрисовки точек, сидит внутри. При этом конвейер приостанавливается до обработки всей модели. Если данных будет очень много, то эльфы, сидящие внутри, не будут успевать перерабатывать такой объем и блокировка конвейера вызовет простой уже центрального процессора, ожидающего, когда конвейер освободится - отсюда мы видим падение fps-ов при большом потоке информации (перекрывающем филлрейт конвейера) и слабом графическом процессоре.

Пример.
Конвейер запущен, Деды Морозы поехали по ленте. И через 5 штук мы вспоминаем, что нам не нужны гламурно-сглаженные, но только рубленные топором, только хардкорные модели на выходе. Подходим к пульту и перещелкиваем первый тумблер (см. выше). Все, все последующие модели будут отрисовываться, словно резчик по дереву был пьян и забыл про шлифовку и прочие доработки. Нам ничего не нужно перещелкивать на пульте перед каждой последующей моделью.
Прибежала Снегурочка, наблюдающая все это непотребство на экране и сказала, что неплохо бы раскрасить Деда Мороза, потому что гламурное розовое нечто с неаккуратными краями смотрится на экране неканонично, хотя ей нравится. Берем у нее фотографию-картинку настоящего Деда Мороза, подсовываем в рамку под тумблером текстурирования и перещелкиваем его. Все, все последующие Деды Морозы будут выглядеть с наложенной картинкой-текстурой и с несглаженными гранями. Нам ничего не нужно перещелкивать на пульте перед каждой последующей моделью.
Снегурочка пришла еще через 10 моделей, уже немного нетрезвая, и заявила, что пусть лучше Дед Мороз будет гламурно ровненьким, но должен иметь сходство с фотографией. ок, перещелкиваем тумблер сглаживания и идем дальше праздновать НГ. На выходе получим текстурированного и сглаженного Деда Мороза для всех последующих моделей. Нам ничего не нужно перещелкивать на пульте перед каждой последующей моделью.

P.S.1. На самом деле OpenGL поддерживает не только треугольные грани, но для унификации всего процесса лучше использовать именно их.
P.S.2. Их не 5, а гораздо больше - в этом смысл конечного автомата OpenGL - много настроек, каждая из которых отвечает за что-то свое и за изменением которых нужно внимательно следить, чтобы не получить Злого Санту, например.
P.S.3. Состояний может быть больше двух, если настройка подразумевает несколько вариантов значений.

Сообщение отредактировал Leopotam - 11.01.13, 10:36



Реп: (503)
очень интересно, но по моему стоит попросить модераторов закрепить эту тему в важных



Реп: (207)
phonecrusher_nik @ 11.01.2013, 11:14 *
очень интересно

что-то, видать, не очень :)



Реп: (503)
Leopotam,
ну не все же хотят чему то научиться, 70% гейм девелоперов с этого сайта все время ищут готовое, а остальные 30% делают сами, вот я например, хочу делать сам, и мне интересно

+ с виду OpenGL это очень сложно, поэтому многие просто мимо проходят



Реп: (295)
phonecrusher_nik @ 11.01.2013, 19:00 *
а остальные 30% делают сами

Да вы, батенька, оптимист.



Реп: (175)
phonecrusher_nik @ 11.01.2013, 21:00 *
ну не все же хотят чему то научиться, 70% гейм девелоперов с этого сайта все время ищут готовое, а остальные 30% делают сами, вот я например, хочу делать сам, и мне интересно


Тут вообще ситуация неоднозначная.

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

С одной стороны более высокая абстракция над Open GL упрощает разработку, с другой стороны, азы и кишки движков тоже надо знать.



Реп: (119)
3. Что скрывается за GLSurfaceView или библиотека EGL. Подробный разбор инициализации OpenGL ES.

За GLSurfaceView скрывается инициализация OpenGL с помощью библиотеки EGL.

EGL - интерфейс между API графического адаптера, таких как OpenGL ES и OpenVG и системой управления окнами платформы. EGL также обеспечивает возможность взаимодействия между API для эффективной передачи данных – например между видеоподсистемой работающей c OpenMAX AL и GPU работающем с OpenGL ES.

EGL предоставляет механизмы для создания поверхности ( Surface ), на которой клиент API, такой как OpenGL ES или OpenVG создает графику. EGL синхронизирует клиент API и родной API визуализации для платформы ( в случае Android это Skia). Это позволяет бесшовную, высокопроизводительную , ускоренную визуализацию с использованием как OpenGL ES так и OpenVG для смешанного режима 2D и 3D-рендеринга.

Cистема управления окнами ( native platform window system ) - оконная система, обеспечивающая стандартные инструменты и протоколы для построения графического интерфейса пользователя. В случае Android это SurfaceFlinger, для *nix это обычно X Window System, MacOs и Windows используют свою, ни с чем не совместимую систему.

В ранних реализациях стандарта OpenGL был пропуск в этапе создания GLSurface поверхности в контексте оконной системы.
Для инициализации приходилось использовать средства самой операционной системы, которые сильно отличались друг от друга и даже не всегда была возможность обеспечить одинаковый вид и функциональность
Нестандартных реализаций было достаточно много — это SDL, GLUT,CPW,NGL и т.д.
Но все же единого стандарта не было.
Библиотека EGL создана для того чтобы закрыть этот пробел.

OpenVG - стандартный API, предназначенный для аппаратно-ускоряемой двухмерной векторной графики. Так как на платформе Android этот API не задействован ( даже странно, почему так ) рассматривать его не буду. =(

Посмотрим что же делает GLSurfaceView( исходник ):

( Выделяю только ключевые моменты )


public class GLSurfaceView extends SurfaceView

Из этой строчки видно что GLSurfaceView является расширением SurfaceView.

SurfaceView предоставляет выделенные поверхности для рисования, встроеную в иерархию Activity. Вы можете управлять форматом этой поверхности и, если хотите, ее размер; SurfaceView заботится о размещении поверхности в нужное место на экране. Соответственно можно размещать view-шки как на обычном SurfaceView или например встроить GLSurfaceView в свой элемент управления.

...
holder.setFormat(PixelFormat.RGB_565);
...

Далее GLSurfaceView задает формат своей поверхности как RGB_565 ( 16bit цвет ).
На это стоит обратить внимание, подробности чуть ниже.

Теперь сама инициализация OpenGL:

...
EGL10 Egl = (EGL10) EGLContext.getEGL();
...

Получение экземпляра враппера EGL.

wrapper ( враппер ) - обёртка библиотеки, является промежуточным слоем между прикладной программой и другой библиотекой или интерфейсом программирования приложений (API).
Целью написания обёртки библиотеки может быть обеспечение работоспособности библиотеки (API) в каком-либо (чаще скриптовым) языке, в котором прямой вызов функций этой библиотеки API затруднителен или невозможен.
В Android классы GLES и EGL являются обертками к нативным библиотекам OpenGL и EGL.

...
mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
...

Получение ссылки на стандартный дисплей.
Дисплеев в системе может быть несколько, если нужен доступ к другим дисплеем константу EGL_DEFAULT_DISPLAY нужно заменить на соответствующею. Все константы кроме EGL_DEFAULT_DISPLAY платформозависимы.

...
int] version = new int[2];
mEgl.eglInitialize(mEglDisplay, version);
...

Инициализация EGL для конкретного дисплея.
Возвращает версию EGL в массиве version].

...
EGLConfig mEglConfig = mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);
...

Выбирается конфигурация OpenGL поверхности.
Это самый важный момент в инициализации OpenGL.
Именно на этом этапе можно задать глубину цвета, буферов, антиалайзинг и еще кучу параметров.
Ниже будет очень подробное описание.

...
mEglContext = egl.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT,mEGLContextClientVersion != 0 ? attrib_list : null);
...

Создаем контекст определенной конфигурации.
Очень "тяжелая" операция.
Именно в этот момент начинает работать часть графического драйвера отвечающего за 3D,
происходит куча проверок, инициализируются большие объемы памяти и т.д.

Все, OpenGL инициализирован.

Теперь создание GLSurface:
...
egl.eglCreateWindowSurface(display, config, nativeWindow, null);
...

Cоздается одним вызовом. nativeWindow - ссылка на поверхность/окно где создастся OpenGLSurface.
( прошу обратить внимание на то что этот метод можно вызвать только из SurfaceView или его наследников из-за ограничения во враппере EGL )

И устанавливает текущей контекст:
...
mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext);
...

Вот и все. Можно рисовать.
OpenGL контекст создается за 7 вызовов EGL.

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

еще одна необходимая функция EGL - смена кадров ( свап буферов ):
...
mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)
...

Тут я думаю все понятно.


Теперь разберемся с конфигурациями GLSurface.

OpenGLSurface конфигурации - это возможность создания OpenGLSurface с разными параметрами, такими как глубина цвета, сглаживание, глубина Z-буфера/трафорета и еще кучей параметров.

Для программиста шаблон конфигурации представляет из себя одномерный массив целых чисел с парами ключ-значение ( записанными последовательно ).
Массив всегда должен заканчивается ключом EGL10.EGL_NONE.

Пример такого массива:
int] configSpec = {
EGL10.EGL_RED_SIZE, 5,
EGL10.EGL_GREEN_SIZE, 6,
EGL10.EGL_BLUE_SIZE, 5,
EGL10.EGL_DEPTH_SIZE, 16,
EGL10.EGL_RENDERABLE_TYPE, 4,
EGL10.EGL_SAMPLE_BUFFERS, 1
EGL10.EGL_SAMPLES, 4,
EGL10.EGL_NONE
};


Возможные ключи конфигурации:
EGL_ALPHA_SIZE
EGL_ALPHA_MASK_SIZE
EGL_BIND_TO_TEXTURE_RGB
EGL_BIND_TO_TEXTURE_RGBA
EGL_BLUE_SIZE
EGL_BUFFER_SIZE
EGL_COLOR_BUFFER_TYPE
EGL_CONFIG_CAVEAT
EGL_CONFIG_ID
EGL_CONFORMANT
EGL_DEPTH_SIZE
EGL_GREEN_SIZE
EGL_LEVEL
EGL_LUMINANCE_SIZE
EGL_MAX_PBUFFER_WIDTH
EGL_MAX_PBUFFER_HEIGHT
EGL_MAX_PBUFFER_PIXELS
EGL_MAX_SWAP_INTERVAL
EGL_MIN_SWAP_INTERVAL
EGL_NATIVE_RENDERABLE
EGL_NATIVE_VISUAL_ID
EGL_NATIVE_VISUAL_TYPE
EGL_RED_SIZE
EGL_RENDERABLE_TYPE
EGL_SAMPLE_BUFFERS
EGL_SAMPLES
EGL_STENCIL_SIZE
EGL_SURFACE_TYPE
EGL_TRANSPARENT_TYPE
EGL_TRANSPARENT_RED_VALUE
EGL_TRANSPARENT_GREEN_VALUE
EGL_TRANSPARENT_BLUE_VALUE
...

+ еще существуют вендорозависимые ключи,
такие как EGL_COVERAGE_BUFFERS_NV ( сглаживание для чипов Tegra и других ).


Для нас важными являются только несколько ключей:

EGL_RED_SIZE - бит на красный канал
EGL_GREEN_SIZE -бит на зеленый канал
EGL_BLUE_SIZE - бит на синий канал
EGL_ALPHA_SIZE - бит на альфа канал
EGL_DEPTH_SIZE - глубина Z буфера
EGL_RENDERABLE_TYPE - API поддерживаемые в данной конфигурации. Значение - битовая маска, так как одной и той же конфигурации может соответствовать несколько API. OpenGL ES 2.0 соответствует значение 4
EGL_SAMPLE_BUFFERS - Поддержка антиалайзинга
EGL_SAMPLES - количество семплов на пиксель
EGL_NONE - завершение списка

Как это все работает:
// Создаем шаблон конфигурации с [B]минимальными[/B] требуемыми параметрами
int] configSpec = {
EGL10.EGL_RED_SIZE, 5, // минимум 16битный цвет
EGL10.EGL_GREEN_SIZE, 6,
EGL10.EGL_BLUE_SIZE, 5,
EGL10.EGL_DEPTH_SIZE, 16, // Глубина Z буффера минимум 16бита
EGL10.EGL_RENDERABLE_TYPE, 4, // поддержка GLES20
EGL10.EGL_SAMPLE_BUFFERS, 1, // поддержка антиалайзинга
EGL10.EGL_SAMPLES, 2, // минимум 2 семпла
EGL10.EGL_NONE
};

// Запрашиваем список подходящих конфигураций
//
mValue = new int[1];
egl.eglChooseConfig(display, configSpec, null, 0,mValue);
int numConfigs = mValue[0]; // получаем количество конфигов подходящих под наше описание.
// так как шаблон конфигурации задает МИНИМАЛЬНЫЕ требования
//то в данном случае в список попадут конфигурации и с 32битным цветом и со сглаживанием например на 4 ( или 8 ) сэмплов.

if(numConfigs <= 0){
EGLConfig] configs = new EGLConfig[numConfigs];
egl.eglChooseConfig(display, configSpec, configs, numConfigs,mValue); // Получаем список конфигураций.
// Теперь у нас есть заполненный массив конфигураций configs
}else{Конфигураций соответствующих шаблону не найдено.}


Важно:

Когда более чем одна конфигурация буфера кадра соответствует шаблону, возвращается список конфигураций. Список сортируется в соответствии со следующими правилами приоритета, которые применяются в порядке:

1.по EGL_CONFIG_CAVEAT, в следующем порядке: EGL_NONE, EGL_SLOW_CONFIG и EGL_NON_CONFORMANT_CONFIG.
Например разработчик устройства ( драйвера ) пометил определенные конфигурации как медленные или не рекомендуемые - они окажутся в конце списка.

2. по EGL_COLOR_BUFFER_TYPE, в порядке EGL_RGB_BUFFER, EGL_LUMINANCE_BUFFER ( монохромный ).

3. по сумме числа бит всех каналов RGBA ( или глубине EGL_LUMINANCE_SIZE ). То есть сначала в списке идут конфигурации с максимальной глубиной цвета и далее в порядке уменьшения. На это стоит обратить особое внимание, так как если вы запросили конфигурацию RGB565 без альфа-канала то первыми в списке скорее всего будут конфигурации RGBA8888 ( при одинаковых остальных параметрах ), так как сумма бит всех каналов в них больше.

4. EGL_BUFFER_SIZE в порядке возрастания( то есть сначала будут конфигурации с минимальным значением ).

5. EGL_SAMPLE_BUFFERS в порядке возрастания.

6. EGL_SAMPLES в порядке возрастания.

7. EGL_DEPTH_SIZE в порядке возрастания.

8. EGL_STENCIL_SIZE в порядке возрастания.

9. EGL_ALPHA_MASK_SIZE в порядке возрастания.

10. EGL_NATIVE_VISUAL_TYPE ( тут в зависимости от реализации, обычно одно значение ).

10. EGL_CONFIG_ID в порядке возрастания (последняя опция сортировки, гарантирующая уникальность).

Сортировка не производится по ключам:
EGL_BIND_TO_TEXTURE_RGB, EGL_BIND_TO_TEXTURE_RGBA, EGL_CONFORMANT, EGL_LEVEL, EGL_NATIVE_RENDERABLE, EGL_MAX_SWAP_INTERVAL, EGL_MIN_SWAP_INTERVAL, EGL_RENDERABLE_TYPE, EGL_SURFACE_TYPE, EGL_TRANSPARENT_TYPE, EGL_TRANSPARENT_RED_VALUE, EGL_TRANSPARENT_GREEN_VALUE, and EGL_TRANSPARENT_BLUE_VALUE.


Пример. Выводит на экран все доступные конфигурации для OpenGL ES 2.0
import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;

import javax.microedition.khronos.egl.*;

public class MyActivity extends Activity {

final int EGL_COVERAGE_BUFFERS_NV = 0x30E0;
final int EGL_COVERAGE_SAMPLES_NV = 0x30E1;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);

TextView textv = new TextView(this); // TextView c ScrollView для отображения результата
LinearLayout.LayoutParams blp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PAREN
T);
ScrollView scrollv = new ScrollView(this);
scrollv.setLayoutParams(blp);
scrollv.addView(textv);
this.addContentView(scrollv,blp);

EGL10 Egl = (EGL10) EGLContext.getEGL(); // получаем враппер Egl
EGLDisplay EglDisplay = Egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); // получаем ссылку на дисплей
int] version = new int[2]; // массив для получения версии EGL
Egl.eglInitialize(EglDisplay, version); // Инициализация EGL

int] configSpec = { // шаблон конфигурации
EGL10.EGL_RENDERABLE_TYPE, 4, // поддержка GLES20
EGL10.EGL_NONE // конец
};
int] mValue = new int[1];
Egl.eglChooseConfig(EglDisplay, configSpec, null, 0,mValue); // получаем колличество конфигураций подходящих под шаблон
int numConfigs = mValue[0];

EGLConfig] configs = new EGLConfig[numConfigs];
int] num_conf = new int[numConfigs];
Egl.eglChooseConfig(EglDisplay, configSpec, configs, numConfigs,mValue); // получаем массив конфигураций

String text ="EGL version "+version[0]+"."+version[1]+"\n";
text+= printConfigs(configs,EglDisplay,Egl)+"\n";

textv.setText(text);
}

private String printConfigs(EGLConfig] conf,EGLDisplay EglDisplay,EGL10 Egl){
String text="";
for(int i = 0; i < conf.length; i++){
int] value = new int[1];
if (conf[i] != null)
{
text+="==== Config №"+i+" ====\n";
Egl.eglGetConfigAttrib(EglDisplay, conf[i], EGL10.EGL_RED_SIZE, value);
text+="EGL_RED_SIZE = "+value[0]+"\n";
Egl.eglGetConfigAttrib(EglDisplay, conf[i], EGL10.EGL_GREEN_SIZE, value);
text+="EGL_GREEN_SIZE = "+value[0]+"\n";
Egl.eglGetConfigAttrib(EglDisplay, conf[i], EGL10.EGL_BLUE_SIZE, value);
text+="EGL_BLUE_SIZE = "+value[0]+"\n";
Egl.eglGetConfigAttrib(EglDisplay, conf[i], EGL10.EGL_ALPHA_SIZE, value);
text+="EGL_ALPHA_SIZE = "+value[0]+"\n";
Egl.eglGetConfigAttrib(EglDisplay, conf[i], EGL10.EGL_DEPTH_SIZE, value);
text+="EGL_DEPTH_SIZE = "+value[0]+"\n";
Egl.eglGetConfigAttrib(EglDisplay, conf[i], EGL10.EGL_SAMPLE_BUFFERS, value);
text+="EGL_SAMPLE_BUFFERS = "+value[0]+"\n";
Egl.eglGetConfigAttrib(EglDisplay, conf[i], EGL10.EGL_SAMPLES, value);
text+="EGL_SAMPLES = "+value[0]+"\n";
Egl.eglGetConfigAttrib(EglDisplay, conf[i], EGL_COVERAGE_BUFFERS_NV, value);
text+="EGL_COVERAGE_BUFFERS_NV = "+value[0]+"\n";
Egl.eglGetConfigAttrib(EglDisplay, conf[i], EGL_COVERAGE_SAMPLES_NV, value);
text+="EGL_COVERAGE_SAMPLES_NV = "+value[0]+"\n\n";
} else { break; }

}
return text;
}
}



Про антиалайзинг ( сглаживание ):
Антиалайзинг включается на уровне драйвера.
Использование поверхностей с EGL_SAMPLE_BUFFERS задает режим MSAA
EGL_SAMPLES задает количество семплов на пиксель, например при 4 получаем режим MSAAx4
В процессе рендеринга управлять MSAA-сглаживанием нельзя.

EGL_COVERAGE_BUFFERS_NV и EGL_COVERAGE_SAMPLES_NV задают режим CSAA аналогичным образом.
Некоторые чипы, Tegra например, могут работать только с CSAA антиалайзингом.
В процессе рендеринга возможно управлять CSAA.

Но я бы не советовал использовать ни тот ни другой режим - а использовать FXAA.
Он намного "легче" в плане вычислений, просчитывается за один проход постобработки и дает лучший визуальный результат.
FXAA возможен только для OpenGL ES 2.0 и последующих редакций.


Остался один момент.

Вспомните строчку из GLSurfaceView:
...
holder.setFormat(PixelFormat.RGB_565);
...


Что будет если мы попытаемся инициализировать GLSurface в режиме RGBA8888 с на поверхности с PixelFormat.RGB_565?

Варианты:
1. система приведет RGBA8888 к RGB565 и мы получим 16битный цвет без прозрачности.
2. система будет нормально отображать RGBA8888, наплевав на RGB565.
3. Все с треском упадет.

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

Привести SurfaceView нужному формату можно приблизительно таким способом:
...
GLSurfaceView.getHolder().setFormat(PixelFormat.RGBA_8888);
...


И еще, никогда не нужно хомячить и пытаться задействовать максимальную конфигурацию так как за все приходится расплачиваться производительностью.

Вот и все про инициализацию OpenGL ES 2.0.

Далее детальное рассмотрение GLSurfaceView, его методов и субклассов.

Сообщение отредактировал usnavii - 17.01.13, 15:17



Реп: (23)
Одна из немногих тем, которые приятно и полезно читать.



Реп: (50)
usnavii,
один совет, лучше оформляй все в шапке а то так не удобно, и искать потом не придется.



Реп: (119)
Спектра @ 18.01.2013, 14:36 *
дин совет, лучше оформляй все в шапке а то так не удобно, и искать потом не придется.


Я вынес ссылки в первое сообщение ( в самое начало)...
Или как лучше сделать?
------------
Часть предложений корявы =)
Просто переводил с первоисточника ( ENG и т.д. ), а там сам начинаешь уже составлять предложения в стиле языка.
Корявость буду стараться убрать .

Сообщение отредактировал usnavii - 18.01.13, 21:59



Реп: (2)
А продолжение будет?



Реп: (119)
MmX Ice @ 25.01.2013, 14:30 *
А продолжение будет?


Будет.
Сегодня - завтра.

Увы, ППС и другие непреодолимые обстоятельства не дали мне закончить в срок... =(

UPD: не прошло и недели...

Сообщение отредактировал usnavii - 30.01.13, 15:22



Реп: (175)
Я вот портом занимаюсь игрушки сейчас. Весь движок игровой на C++ написан.

И мне вот интересно, что будет быстрее - вся игра на Java или всё-таки на C++ с последующим нативным вызовом?



Реп: (119)
Suvitruf @ 26.01.2013, 00:01 *
И мне вот интересно, что будет быстрее - вся игра на Java или всё-таки на C++ с последующим нативным вызовом?


Конечно C++.
Во всяком случае экономия памяти в несколько раз.
При правильном использовании.

С другой стороны вызовы не намного медленнее, а с учетом средств разработки C++ под андройд...
Это с натяжкой можно назвать средствами. Отладка на уровне прошлого десятилетия прошлого века.



Реп: (80)
есть ли книга по opengl на русском языке? хотелось бы почитать. и кто-нибудь использовал opengl с python? я все установил а рускоязычного материала на данную тему практически не нашел :(



Реп: (119)
flopsik @ 26.01.2013, 21:24 *
есть ли книга по opengl на русском языке? хотелось бы почитать. и кто-нибудь использовал opengl с python?


Куча. про OpenGL.

Но OpenGL ES 2.0 настолько отличается от "простого" OpenGL как старо-русский(сейчас наверное только церковный) от русского.
Вроде бы и смысл понятен, и слова похожие на знакомые, да не то...



Добавлено 27.01.2013, 20:00:

flopsik @ 26.01.2013, 21:24 *
python

Просто интересно, зачем питон?

Сообщение отредактировал usnavii - 30.01.13, 15:23



Реп: (80)
Просто это язык который я лучше всего знаю :) еще на c++ могу прогать, но для освоения чего то нового обычно использую питон 3, хотя 2 тож могу юзать

И на андроиде что лучше использовать opengl или opengl es? И собственно в кратце в чем зазница?


Полная версия   Текстовая версия

Помощь   Правила

Сейчас: 19.03.24, 14:30