
Programujeme pre Android
API operačného systému Android nám ponúka viacero možností vývoja aplikácií, v rámci ktorých plánujeme kresliť 2D/3D grafiku. Už dávno sa pritom nepoužíva nízkoúrovňové (low-level) programovanie, ale hardvérové zariadenia (vrátane GPU) participujúce na výslednom efekte sa programujú na oveľa vyššej úrovni (high-level). Priama komunikácia s koncovými zariadeniami je pritom nahradená komunikáciou s tzv. abstraktnou hardvérovou vrstvou (Hardware Abstraction Layer), ktorá vytvára vzťah medzi aplikáciou a jej API a zmenou fotoelektrických vlastností konkrétnych pixelov obrazovky vedúcich k zmene ich farby.
V predošlej časti seriálu sme opísali možnosť kreslenia pomocou plátna (Canvas) a funkcií štandardného API. Teraz sa zameriame na ďalší, omnoho efektívnejší spôsob, ktorým je rendering s využitím funkcií grafickej knižnice OpenGL ES (GLES).
Obr. 1 Zjednodušená architektúra grafického systému OS Android
Grafický systém Androidu
V grafickom systéme Androidu existujú tzv. producenti a konzumenti obsahu grafických zásobníkov (buffers). Systém nie je bezpodmienečne závislý od hardvérovo akcelerovaného renderingu aj napriek tomu, že GPU sa využíva v mnohých procesných krokoch. Hardvérová akcelerácia je konzumentom väčšieho množstva pamäte a nie vždy vedie k zvýšeniu počtu tzv. framerate = FPS (frames per second). Každopádne GPU a akcelerácia boli doplnené a sú nevyhnutné v prípade zariadení s vyšším rozlíšením obrazovky, ktoré sú čoraz rozšírenejšie.
GPU akceleruje grafické operácie, a to najmä v prípade vyššieho počtu renderovaných pixelov, teda pri vyššom rozlíšení obrazovky. Principiálny základ urýchľovania je paralelizmus. GPU je momentálne súčasťou všetkých androidových zariadení a je nevyhnutný na chod GLES2.0 a HWUI (HW akcelerované používateľské rozhranie).
Neoddeliteľnou súčasťou grafického systému Androidu sú:
1. PixelFlinger – rozhranie, resp. softvérový GPU implementujúci GLES1.x,
2. CodeFlinger – kompilátor JIT urýchľujúci rendering pomocou generácie nízkoúrovňového kódu,
3. SurfaceFlinger – tzv. sadzač (compositor), ktorý spravuje viacero plôch (surfaces) viacerých aktivít, plocha pritom predstavuje neviditeľný zásobník, resp. textúru, do ktorej sú renderované pixely.
GLES
Knižnica (štandard, rozhranie, API...) OpenGL a konkrétne jej zjednodušený variant pre tzv. vstavané zariadenia (Embedded Systems) umožňuje Androidu s prehľadom riešiť vysokovýkonný (high-performance) rendering 2D/3D grafiky. Funkcie GLES možno volať buď priamo z Android SDK, alebo cestou NDK (Native Development Kit). Knižnica GLES1.x je podporovaná od Android v1.0 (API Level 1), GLES2.0 od v2.2 (Froyo – API Level 8), GLES3.0 od v4.3 + je nevyhnutná implementácia výrobcom (Jelly Bean – API level 18) a GLES3.1 od v5.0 (Lollipop – API level 21).
Najmarkantnejší rozdiel medzi GLES1.x a vyššími verziami je podpora a takisto nutnosť použitia tzv. shaderových programov. Absencia pevne nastavenej renderovacej cesty (fixed pipeline) a nevyhnutnosť použitia shaderov robí vývoj náročnejším, ale takýto prístup má nespočetné množstvo výhod, z ktorých najvýznamnejšia je flexibilita.
Knižnica GLES3.0 je spätne kompatibilná s GLES2.0, čo znamená, že v našich aplikáciách pracujúcich s GLES2.0 dokážeme využiť niektoré hardvérovo implementované funkcie GLES3.0.
Komponenty GLES
Pri programovaní androidových aplikácií s využitím GLES budeme pracovať najmä s nasledujúcimi komponentmi:
GLSurfaceView |
Trieda podobná SurfaceView slúžiaca na kreslenie grafiky s využitím GLES |
GLSurfaceView.Renderer |
Rozhranie deklarujúce metódy, ktoré sú potrebné na rendering do GLSurfaceView, musíme implementovať metódy onSurfaceCreated(), onSurfaceChanged() a onDrawFrame() |
javax.microedition.khronos.opengles (GL1.x), android.opengl (GLES1.x, GLES2.0, GLES3.0, GLES3.1) |
Rozhrania pre korešpondujúce verzie GLES |
ETC1, ETC2, ASTC, ATC, PVRTC, DXTC, S3TC |
Podporované formáty určené na prácu s komprimovanými textúrami (závislé od zariadenia) |
AEP (Android Extension Pack) |
Štandardná skupina rozšírení |
Programovanie
1. Drvivá väčšina moderných zariadení podporuje GLES2.0, a preto je táto verzia odporúčanou verziou pre naše aplikácie. Pretože nie všetky zariadenia podporujú všetky verzie GLES, je korektné zahrnúť konkrétnu požiadavku do manifestu:
2. Pokračujeme prípravou shaderového programu s jeho vertex a fragment shadermi. Program neskôr použijeme pred kreslením objektov zavolaním metódy glUseProgram():
int náš_vertex_shader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
GLES20.glShaderSource(náš_vertex_shader, kód_vertex_shadera);
GLES20.glCompileShader(náš_vertex_shader);
int náš_fragment_shader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
GLES20.glShaderSource(náš_fragment_shader, kód_fragment_shadera);
GLES20.glCompileShader(náš_fragment_shader);
náš_program = GLES20.glCreateProgram();
GLES20.glAttachShader(náš_program, náš_vertex_shader);
GLES20.glAttachShader(náš_program, náš_fragment_shader);
GLES20.glLinkProgram(náš_program);
3. View aktivity, do ktorého budeme kresliť s využitím GLES, nastavíme metódou setContentView():
class naša_aktivita extends Activity {
GLSurfaceView GLESview;
@Override
public void onCreate(Bundle savedInstanceState) {
GLESview = new náš_GLESview(this);
setContentView(GLESview);
}
}
4. V našom GLESView vytvoríme kontext GLES2.0 a nastavíme renderer:
class náš_GLESview extends GLSurfaceView {
setEGLContextClientVersion(2);
setRenderer(náš_renderer);
}
5. V rendereri implementujeme metódy onSurfaceCreated(), onSurfaceChanged() a onDrawFrame():
class náš_renderer implements GLSurfaceView.Renderer {
// nastavenie stavového stroja GLES
public void onSurfaceCreated() { ... }
// úprava zobrazenia napr. po zmene orientácie
public void onSurfaceChanged() { ... }
// kreslenie
public void onDrawFrame() { ... }
}
Obr. 2 Jednoduchý príklad využitia GLES
Zobrazit Galériu