Použití knihoven OpenVG a EGL (nejenom) na Raspberry Pi

Pavel Tišnovský 25. 2. 2016

Dnešní článek o počítačové grafice na Raspberry Pi bude zaměřen na vysvětlení základních postupů využívaných v knihovně EGL. Ukážeme si inicializaci EGL i způsob zjištění dostupných konfigurací framebufferu.

Obsah

1. Použití knihoven OpenVG a EGL (nejenom) na Raspberry Pi

2. Základní datové typy a objekty, s nimiž se v EGL pracuje

3. Datová struktura se stavem EGL, kterou použijeme v demonstračních příkladech

4. Inicializace a finalizace EGL

5. První demonstrační příklad – inicializace a finalizace EGL

6. Funkce eglGetConfigs()

7. Funkce eglGetConfigAttrib()

8. Zjištění základních informací o konfiguraci framebufferu

9. Druhý demonstrační příklad – výpis základních informací o konfiguraci framebufferu

10. Výsledky vypsané druhým demonstračním příkladem

11. Informace o Z-bufferu, stencil bufferu a o možnosti navázání barvových bufferů na textury

12. Třetí demonstrační příklad – výpis podrobnějších informací o konfiguraci framebufferu

13. Výsledky vypsané třetím demonstračním příkladem

14. Obsah následující části seriálu

15. Repositář s demonstračními příklady

16. Odkazy na Internetu

1. Použití knihoven OpenVG a EGL (nejenom) na Raspberry Pi

V dnešním článku o programování počítačové grafiky (nejenom) na jednodeskovém mikropočítači Raspberry Pi si přiblížíme problematiku použití knihovny EGL a následně pak v navazující části i knihovny OpenVG. Připomeňme si, že EGL neboli též Native Platform Interface, tvoří mezivrstvu mezi grafickým procesorem (přičemž každý grafický procesor může mít zcela odlišný způsob ovládání) a systémem pro správu oken na jedné straně a knihovnou OpenGL, OpenVG či OpenGL ES na straně druhé. Díky použití EGL je možné zajistit, aby se v knihovnách OpenGL, OpenVG a OpenGL ES nemusely implementovat a samozřejmě ani specifikovat funkce určené pro otevření okna či funkce pro zpřístupnění framebufferu; dokonce tyto knihovny ani nemusí poskytovat funkce pro zjištění schopností grafického subsystému. Před vznikem EGL byla situace poměrně komplikovaná, protože všechny aplikace, které například volaly funkce OpenGL, musely nějakým způsobem otevřít okno, získat přístup k vykreslovací ploše atd. K tomu se používaly různé knihovny a rozhraní: SDL, WinAPI, GLX, GLUT. S využitím EGL se situace zjednodušuje, což je patrné z následujícího diagramu, kde můžeme vidět použití EGL na třech odlišných platformách:

+-----------+                       +---------------------------------+
| OpenGL    |........       ........| Linux (Display, Pixmap, Window) |
+-----------+        \     /        +---------------------------------+
                      \   /
+-----------+        +-----+        +---------------------------------+
| OpenGL ES |........| EGL |........| Windows (HDC, HBITMAP, HWND)    |
+-----------+        +-----+        +---------------------------------+
                      /   \
+-----------+        /     \        +---------------------------------+
| OpenVG    |......./       \.......| Android (ANativeWindow, ...)    |
+-----------+                       +---------------------------------+

Za vývojem knihovny EGL stojí sdružení Khronos, které kromě této knihovny „pečuje“ i o specifikace a implementace OpenGL, OpenGL ES, OpenVG, dnes tak populárního nástupce OpenGL jménem Vulkan atd. (viz též https://www.khronos.org/). Jedním ze základních úkolů, které musí knihovna EGL zabezpečit, je vytvoření a správa grafického kontextu, ploch (surface), do kterých je možné přes knihovny OpenGL ES a OpenVG provádět vykreslování atd. Mimochodem – plochy (surface) mohou být vytvořeny tak, aby aplikace běžela v systému X Window (i v okně), přes framebuffer nebo lze vykreslování provádět do zadního bufferu. Další důležitou funkcí nabízenou EGL je kopie obsahu bitmap mezi jednotlivými plochami, tj. operace typu bitblt. Zapomenout nesmíme ani na funkce pro zjištění či nastavení konfigurace grafického subsystému, ostatně právě tyto funkce budou použity v dnešních třech demonstračních příkladech.

2. Základní datové typy a objekty, s nimiž se v EGL pracuje

V hlavičkovém souboru dodávaném s knihovnou EGL nalezneme několik deklarací datových typů použitých při volání funkcí EGL. Tyto datové typy jsou vypsány v následující tabulce společně s jejich stručným popisem. Posledních pět typů je sice deklarovaných jako ukazatele (typu void*), interně se však samozřejmě jedná o záznamy (struct), jejichž vnitřní struktura se ve specifikaci nepopisuje (a ani nás vlastně nezajímá):

# Typ v C Jméno typu Stručný popis
1 unsigned int EGLBoolean může nabývat jen hodnot EGL_TRUE nebo EGL_FALSE, typicky výsledek (návratová hodnota) mnoha funkcí
2 unsigned int EGLenum použito pro všechny symbolické konstanty i bitové masky
3 int32_t EGLint celé číslo, použito v mnoha funkcích
4 void * EGLConfig popisuje formát, typ a velikost bufferů
5 void * EGLContext udržuje takzvaný kontext, který propojuje stav na klientovi a serveru
6 void * EGLDisplay abstraktní displej, na RPi displej jde o konkrétní displej připojený k počítači (teoreticky ale lze vykreslovat i do paměti apod.)
7 void * EGLSurface buffer, do něhož se vykresluje (je buď viditelný nebo tzv.off-screen)
8 void * EGLClientBuffer buffer na klientovi, použito právě v OpenVG pro kreslení

Poznámka: jak jste asi (správně) poznali, budu se v dalším textu soustředit na programování v céčku, takže vlastně navážeme na předchozí části seriálu, kde jsme použili céčko pro přístup do framebufferu Raspberry Pi.

3. Datová struktura se stavem EGL, kterou použijeme v demonstračních příkladech

Ve všech demonstračních příkladech bude stav EGL (a vlastně i stav celé grafické pipeline) reprezentován jednoduchým záznamem (struct), jehož struktura vypadá následovně:

/*
 * Datova struktura obsahujici cely stav EGL "sezeni".
 */
typedef struct
{
    uint32_t screen_width;
    uint32_t screen_height;
 
    uint32_t window_x;
    uint32_t window_y;
    int32_t  window_width;
    int32_t  window_height;
 
    EGLDisplay display;
    EGLSurface surface;
    EGLContext context;
    EGLConfig  config;
} EGL_STATE_T;

Způsob korektního naplnění většiny prvků této datové struktury si ukážeme až příště, protože se bude jednat o poměrně dlouhý programový kód. Nicméně význam by měl být zřejmý: budeme si pamatovat rozměry obrazovky, rozměry okna, do něhož se bude vykreslovat a taktéž aktuální konfiguraci EGL, přiřazený displej (ten je u Raspberry Pi jen jeden), vykreslovací plochu (pokud bude vytvořena) a taktéž kontext propojující stav klienta (OpenGL/OpenVG/OpenGL ES) a serveru (což zde znamená stav okenního systému a grafického procesoru).

4. Inicializace a finalizace EGL

Při používání knihovny EGL je nutné nejdříve provést její inicializaci a při ukončení práce taktéž takzvanou „finalizaci“. V případě inicializace se postupně provádí několik kroků. Typickým prvním krokem je získání datové struktury popisující primární displej, dále pak vlastní inicializace interních datových struktur EGL, napojení některé z knihoven OpenGL, OpenGL ES nebo OpenVG na EGL a nakonec i získání přístupu k plochám (surface), do nichž je možné provádět vykreslování (na tomto místě se může vývojář rozhodnout, zda preferuje vykreslování do okna či naopak vykreslování na celou obrazovku, což se pochopitelně týká především počítačových her, přehrávačů videa apod.). Ve skutečnosti je celá inicializace poměrně složitá (jedná se o více než 100 řádků programového kódu, pokud počítáme i reakci na chyby), takže se většina vývojářů spolehne na další knihovnu, která inicializaci provede za ně. My prozatím takový luxus nevyužijeme, ale postupně si všechny důležité kroky popíšeme a ukážeme.

První důležitou funkcí volanou při inicializaci je funkce nazvaná eglGetDisplay(), která slouží pro získání datové struktury popisující zvolený reálný či virtuální displej:

EGLDisplay eglGetDisplay(
    NativeDisplayType native_display);

Na mikropočítači Raspberry Pi a dalších počítačích s jediným displejem se této funkci předává konstanta EGL_DEFAULT_DISPLAY. V případě chyby se vrátí hodnota EGL_NO_DISPLAY, jakákoli odlišná hodnota znamená skutečný displej.

Poznámka: návratová hodnota funkce eglGetDisplay() je velmi důležitá, protože se předává do prakticky všech dalších funkcí knihovny EGL.

Druhou funkcí používanou při inicializaci knihovny EGL je funkce eglInitialize(). V prvním parametru se předává (primární) displej, druhé dva parametry jsou ukazatele na celočíselné proměnné, které mohou být naplněny verzí knihovny EGL. Pokud nás tato informace nezajímá, mohou být namísto ukazatelů předány konstanty NULL. Výsledkem této funkce je pravdivostní hodnota značící, zda se inicializace podařila či nikoli:

EGLBoolean eglInitialize(
    EGLDisplay display,
    EGLint * major,
    EGLint * minor);

Základní inicializace knihovny EGL (prozatím bez bufferů a kreslicích ploch) bude vypadat takto:

/*
 * Inicializace EGL.
 */
void initialize_egl(EGL_STATE_T *state)
{
    EGLBoolean result;
 
    /* nutne pro RPi */
    bcm_host_init();
 
    /* pro jistotu vymazeme datovou strukturu nesouci stav EGL */
    memset(state, 0, sizeof(*state));
 
    /* propojeni na vychozi displej */
    state->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
 
    /* inicializace displeje */
    result = eglInitialize(state->display, NULL, NULL);
 
    /* kontrola, zda inicializace probehla v poradku */
    if (result == EGL_FALSE) {
        puts("EGL init failed");
        exit(1);
    }
}

Důvody vedoucí k nutnosti napsání programového kódu, který provádí inicializaci EGL a její napojení na OpenGL, OpenGL ES či OpenVG, jsou pochopitelné. Ovšem stejně důležitá je i „finalizace“ prováděná ve chvíli, kdy se má aplikace ukončit. Ve fázi finalizace je nutné uvolnit všechnu paměť používanou GPU, což se týká jak samotného framebufferu, tak i případných textur apod. Dále je nutné aplikaci odpojit od vykreslovací plochy i primárního displeje, takže se tyto systémové prostředky uvolní a může je začít používat další aplikace. „Finalizace“ může vypadat následovně:

/*
 * Ukonceni prace s EGL.
 */
void finalize_egl(EGL_STATE_T *state)
{
    eglSwapBuffers(state->display, state->surface);
    eglMakeCurrent(state->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    eglDestroySurface(state->display, state->surface);
    eglDestroyContext(state->display, state->context);
    eglTerminate(state->display);
}

Vidíme, že se provádí tyto kroky:

  1. Prohození předního a zadního bufferu (tímto se vynutí dokončení všech operací v grafické pipeline).
  2. Odstranění vazby na výchozí kreslicí plochu.
  3. Uvolnění kreslicí plochy (pokud existuje).
  4. Uvolnění kontextu mezi EGL a další knihovnou (OpenGL/OpenGL ES/OpenVG).
  5. Vlastní ukončení knihovny EGL.

V dnešních příkladech sice „finalizátor“ budeme volat, ovšem ve skutečnosti by postačovalo zavolat jen poslední funkci.

5. První demonstrační příklad – inicializace a finalizace EGL

Funkce, které jsme si popsali v předchozích kapitolách, jsou použity v dnešním prvním demonstračním příkladu, který je vlastně velmi jednoduchý, protože obsahuje jen základní inicializaci a finalizaci EGL. V příkladu je použita již zmíněná datová struktura držící informace o stavu EGL, přičemž většina prvků této struktury není prozatím použita (ovšem příště již všechny prvky využijeme). Nejprve se podívejme na úplný zdrojový kód tohoto příkladu, v němž upozorním především na řádek, který je specifický pro Raspberry Pi. Jedná se o řádek s voláním funkce bcm_host_init(), jejíž hlavičku nalezneme v souboru bcm_host.h:

/* OpenVG (nejenom) na Raspberry Pi - prvni demonstracni priklad */
 
#include <stdio.h>
 
#include <VG/openvg.h>
#include <VG/vgu.h>
#include <EGL/egl.h>
#include <bcm_host.h>
 
 
 
/*
 * Datova struktura obsahujici cely stav EGL "sezeni".
 */
typedef struct
{
    uint32_t screen_width;
    uint32_t screen_height;
 
    uint32_t window_x;
    uint32_t window_y;
    int32_t  window_width;
    int32_t  window_height;
 
    EGLDisplay display;
    EGLSurface surface;
    EGLContext context;
    EGLConfig  config;
} EGL_STATE_T;
 
 
 
/*
 * Inicializace EGL.
 */
void initialize_egl(EGL_STATE_T *state)
{
    EGLBoolean result;
 
    /* nutne pro RPi */
    bcm_host_init();
 
    /* pro jistotu vymazeme datovou strukturu nesouci stav EGL */
    memset(state, 0, sizeof(*state));
 
    /* propojeni na vychozi displej */
    state->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
 
    /* inicializace displeje */
    result = eglInitialize(state->display, NULL, NULL);
 
    /* kontrola, zda inicializace probehla v poradku */
    if (result == EGL_FALSE) {
        puts("EGL init failed");
        exit(1);
    }
}
 
 
 
/*
 * Ukonceni prace s EGL.
 */
void finalize_egl(EGL_STATE_T *state)
{
    /* nyni jsou tyto kroky prozatim zbytecne, v dalsich prikladech se vsak budou hodit */
    eglSwapBuffers(state->display, state->surface);
    eglMakeCurrent(state->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    eglDestroySurface(state->display, state->surface);
    eglDestroyContext(state->display, state->context);
    eglTerminate(state->display);
}
 
 
 
/*
 * Vstupni bod do programu.
 */
int main(int argc, char *argv[])
{
    EGL_STATE_T egl_state;
 
    initialize_egl(&egl_state);
    puts("initialize_egl OK");
 
    finalize_egl(&egl_state);
    puts("finalize_egl OK");
 
    return 0;
}

Jakým způsobem se tento demonstrační příklad překládá? Předpokládejme, že je použita standardní instalace Raspbianu. Na tomto systému je přítomen v určitém ohledu speciální adresář /opt/vc/, v němž jsou kromě několika dem (podle mého názoru zbytečně komplikovaných :-) uloženy i hlavičkové soubory a knihovny, které jsou v příkladu použity. Abychom se vyhnuli nutnosti předávání parametrů na příkazové řádce, bude lepší použít následující Makefile soubor. Celý překlad se potom provede jednoduše příkazem make, adresář dostaneme do původního stavu příkazem make clean:

# Makefile pro preklad tretiho prikladu ukazujiciho
# praci s OpenVG a EGL.
 
# Parametry prekladace.
CFLAGS=-Wall
 
# Dalsi parametry prekladace, zde adresare, kde se maji 
# hledat hlavickove soubory.
INCLUDES=-I/opt/vc/include/ -I/opt/vc/include/interface/vcos/pthreads -I/opt/vc/include/interface/vmcs_host/linux
 
# Parametry linkeru.
LDFLAGS=-L/opt/vc/lib/ -lGLESv2 -lEGL -lopenmaxil -lbcm_host -lvcos -lvchiq_arm -lpthread -lrt -lm
 
PROGNAME=example1
 
# Vychozi pravidlo pro vytvoreni vysledne spustitelne aplikace.
all:    $(PROGNAME)
 
clean:
        rm -f *.o
        rm -f $(PROGNAME)
 
# Pravidlo pro slinkovani vsech objektovych souboru a vytvoreni
# vysledne spustitelne aplikace.
$(PROGNAME):    $(PROGNAME).o
        $(CC) -o $@ $(LDFLAGS) $<
 
# Pravidlo pro preklad kazdeho zdrojoveho souboru do prislusneho
# objektoveho souboru.
%.o:    %.c
        $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@

Poznámka: hlavičkové soubory uložené v adresáři /opt/vc/ jsou napsány takovým způsobem, že při překladu není možné použít přepínač -ansi.

6. Funkce eglGetConfigs()

Ještě předtím, než je možné zahájit vykreslování (například s použitím OpenVG), je nutné zjistit všechny dostupné konfigurace framebufferu a vybrat z nich tu správnou konfiguraci (bitovou hloubku barvového bufferu, bitovou hloubku Z-bufferu, stencil bufferu atd.). K tomuto účelu slouží funkce nazvaná eglGetConfigs():

EGLBoolean eglGetConfigs(
    EGLDisplay   display,
    EGLConfig  * configs,
    EGLint       config_size,
    EGLint     * num_config);

Typicky se tato funkce volá dvakrát. Poprvé se jí ve druhém parametru předá hodnota NULL. V tomto případě funkce eglGetConfigs() do proměnné, jejíž adresa je předána v posledním parametru, vloží celkový dostupný počet konfigurací. Tato hodnota se následně použije pro alokaci pole prvků typu EGLConfig. Při druhém volání funkce eglGetConfigs() se toto pole předá ve druhém parametru (pole==adresa prvního prvku, což nikdy nebude NULL) a následně je toto pole naplněno (přesněji řečeno se naplní maximálně config_size položek).

Pokud tato funkce z nějakého důvodu skončí s chybou, vrátí se hodnota EGL_FALSE a současně nedojde ke změně datových struktur a proměnných, jejichž ukazatele jsou předány ve druhém a čtvrtém parametru. Pokud naopak funkce skončí v pořádku, vrátí se podle očekávání hodnota EGL_TRUE a obě datové struktury by měly být nastaveny správně.

7. Funkce eglGetConfigAttrib()

Pole získané funkcí eglGetConfigs() obsahuje prvky typu EGLConfig, přičemž každý prvek popisuje jednu možnou (či možná lépe řečeno dostupnou) konfiguraci framebufferu. Pro získání jednotlivých atributů každé konfigurace je nutné použít funkci nazvanou eglGetConfigAttrib(), jejíž hlavička vypadá následovně:

EGLBoolean eglGetConfigAttrib(
    EGLDisplay display,
    EGLConfig  config,
    EGLint     attribute,
    EGLint    *value);

Význam prvního parametru již známe. Druhým parametrem je jeden z prvků pole přečteného přes eglGetConfigs(), třetím parametrem konstanta představující jméno atributu (viz též další kapitolu) a v posledním parametru se předává adresa proměnné. Tato proměnná je naplněna hodnotou vybraného atributu (samozřejmě jen v případě, že funkce neskončí s chybou).

V následující tabulce jsou vypsány konstanty představující symbolická jména atributů. Tyto konstanty se předávají ve třetím parametru:

Symbolická konstanta
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

V případě, že tato funkce skončí s chybou, vrátí se hodnota EGL_FALSE a současně nedojde ke změně hodnoty proměnné, jejíž ukazatel byl předán ve čtvrtém parametru. Pokud naopak funkce skončí v pořádku, vrátí se podle očekávání hodnota EGL_TRUE a proměnná bude nastavena korektně.

8. Zjištění základních informací o konfiguraci framebufferu

Podívejme se nyní na postup používaný pro zjištění základních informací o barvovém bufferu, což je jedna součást celého framebufferu sloužící pro uložení zobrazované scény (v případě knihovny OpenVG potřebujeme pouze barvový buffer!). Nejprve zjistíme počet všech dostupných konfigurací (druhý parametr je NULL):

/* precteni poctu konfiguraci dostupnych pres EGL */
/* pocet se ulozi do promenne configurations_count */
eglGetConfigs(state->display, NULL, 0, &configurations_count);
printf("EGL has %d configurations available\n", configurations_count);

Následně se alokuje pole s prvky typu EGLConfig a prvky tohoto pole se naplní aktuálními konfiguracemi (druhý parametr je ukazatel na první prvek pole):

/* nacteni vsech konfiguraci do pripraveneho pole */
all_configurations = malloc(configurations_count * sizeof(*all_configurations));
eglGetConfigs(state->display, all_configurations, configurations_count, &configurations_count);

Nyní v programové smyčce procházíme všemi prvky pole a voláme funkci, která vypíše základní atributy:

int i;
for (i = 0; i < configurations_count; i++) {
    printf("%3d            ", i);
    print_egl_configuration(state->display, &all_configurations[i]);
}

Samotná volaná funkce je již jednoduchá – nejprve přečte všechny hledané atributy:

int red, green, blue, alpha, buffer;
 
eglGetConfigAttrib(display, *config, EGL_RED_SIZE, &red);
eglGetConfigAttrib(display, *config, EGL_GREEN_SIZE, &green);
eglGetConfigAttrib(display, *config, EGL_BLUE_SIZE, &blue);
eglGetConfigAttrib(display, *config, EGL_ALPHA_SIZE, &alpha);
eglGetConfigAttrib(display, *config, EGL_BUFFER_SIZE, &buffer);

A posléze jejich hodnoty vypíše na standardní výstup:

if (alpha) {
    printf("%1d   %1d   %1d   %1d   %2d\n", red, green, blue, alpha, buffer);
}
else {
    printf("%1d   %1d   %1d   x   %2d\n", red, green, blue, buffer);
}

Na konci jenom pro pořádek dealokujeme pole s konfiguracemi:

free(all_configurations);

9. Druhý demonstrační příklad – výpis základních informací o konfiguraci framebufferu

Obě funkce popsané v předchozích třech kapitolách jsou použity v dnešním druhém demonstračním příkladu pro zjištění a následný výpis základních informací o dostupných konfiguracích framebufferu. Nejprve je provedena inicializace knihovny EGL, následně se zjistí počet dostupných konfigurací, tyto konfigurace se načtou do pole a nakonec se pro každý prvek tohoto pole zjistí pět atributů: počet bitů rezervovaných pro červenou barvovou složku, počet bitů rezervovaných pro zelenou barvovou složku, počet bitů rezervovaných pro modrou barvovou složku, počet bitů rezervovaných pro alfa kanál (průhlednost pixelu) a konečně celková bitová hloubka barvového bufferu. Následuje výpis zdrojového kódu tohoto demonstračního příkladu:

/* OpenVG (nejenom) na Raspberry Pi - druhy demonstracni priklad */
 
#include <stdio.h>
 
#include <VG/openvg.h>
#include <VG/vgu.h>
#include <EGL/egl.h>
#include <bcm_host.h>
 
 
 
/*
 * Datova struktura obsahujici cely stav EGL "sezeni".
 */
typedef struct
{
    uint32_t screen_width;
    uint32_t screen_height;
 
    uint32_t window_x;
    uint32_t window_y;
    int32_t  window_width;
    int32_t  window_height;
 
    EGLDisplay display;
    EGLSurface surface;
    EGLContext context;
    EGLConfig  config;
} EGL_STATE_T;
 
 
 
/*
 * Vypis konfigurace displeje nabizene pres EGL
 */
void print_egl_configuration(EGLDisplay display, EGLConfig *config)
{
    int red, green, blue, alpha, buffer;
 
    eglGetConfigAttrib(display, *config, EGL_RED_SIZE, &red);
    eglGetConfigAttrib(display, *config, EGL_GREEN_SIZE, &green);
    eglGetConfigAttrib(display, *config, EGL_BLUE_SIZE, &blue);
    eglGetConfigAttrib(display, *config, EGL_ALPHA_SIZE, &alpha);
    eglGetConfigAttrib(display, *config, EGL_BUFFER_SIZE, &buffer);
    if (alpha) {
        printf("%1d   %1d   %1d   %1d   %2d\n", red, green, blue, alpha, buffer);
    }
    else {
        printf("%1d   %1d   %1d   x   %2d\n", red, green, blue, buffer);
    }
}
 
 
 
/*
 * Inicializace EGL.
 */
void initialize_egl(EGL_STATE_T *state)
{
    EGLBoolean result;
    EGLint     configurations_count;
    EGLConfig *all_configurations;
 
    /* nutne pro RPi */
    bcm_host_init();
 
    /* pro jistotu vymazeme datovou strukturu nesouci stav EGL */
    memset(state, 0, sizeof(*state));
 
    /* propojeni na vychozi displej */
    state->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
 
    /* inicializace displeje */
    result = eglInitialize(state->display, NULL, NULL);
 
    /* kontrola, zda inicializace probehla v poradku */
    if (result == EGL_FALSE) {
        puts("EGL init failed");
        exit(1);
    }
 
    /* precteni poctu konfiguraci dostupnych pres EGL */
    eglGetConfigs(state->display, NULL, 0, &configurations_count);
    printf("EGL has %d configurations available\n", configurations_count);
 
    /* nacteni vsech konfiguraci do pripraveneho pole */
    all_configurations = malloc(configurations_count * sizeof(*all_configurations));
    eglGetConfigs(state->display, all_configurations, configurations_count, &configurations_count);
 
    puts("Configuration  R   G   B   A   bpp");
    /* postupny vypis vsech konfiguraci */
    int i;
    for (i = 0; i < configurations_count; i++) {
        printf("%3d            ", i);
        print_egl_configuration(state->display, &all_configurations[i]);
    }
    free(all_configurations);
}
 
 
 
/*
 * Ukonceni prace s EGL.
 */
void finalize_egl(EGL_STATE_T *state)
{
    /* nyni jsou tyto kroky prozatim zbytecne, v dalsich prikladech se vsak budou hodit */
    eglSwapBuffers(state->display, state->surface);
    eglMakeCurrent(state->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    eglDestroySurface(state->display, state->surface);
    eglDestroyContext(state->display, state->context);
    eglTerminate(state->display);
}
 
 
 
/*
 * Vstupni bod do programu.
 */
int main(int argc, char *argv[])
{
    EGL_STATE_T egl_state;
 
    initialize_egl(&egl_state);
    puts("initialize_egl OK");
 
    finalize_egl(&egl_state);
    puts("finalize_egl OK");
 
    return 0;
}

Soubor Makefile je prakticky shodný se souborem použitým v prvním demonstračním příkladu:

# Makefile pro preklad tretiho prikladu ukazujiciho
# praci s OpenVG a EGL.
 
# Parametry prekladace.
CFLAGS=-Wall
 
# Dalsi parametry prekladace, zde adresare, kde se maji 
# hledat hlavickove soubory.
INCLUDES=-I/opt/vc/include/ -I/opt/vc/include/interface/vcos/pthreads -I/opt/vc/include/interface/vmcs_host/linux
 
# Parametry linkeru.
LDFLAGS=-L/opt/vc/lib/ -lGLESv2 -lEGL -lopenmaxil -lbcm_host -lvcos -lvchiq_arm -lpthread -lrt -lm
 
PROGNAME=example2
 
# Vychozi pravidlo pro vytvoreni vysledne spustitelne aplikace.
all:    $(PROGNAME)
 
clean:
        rm -f *.o
        rm -f $(PROGNAME)
 
# Pravidlo pro slinkovani vsech objektovych souboru a vytvoreni
# vysledne spustitelne aplikace.
$(PROGNAME):    $(PROGNAME).o
        $(CC) -o $@ $(LDFLAGS) $<
 
# Pravidlo pro preklad kazdeho zdrojoveho souboru do prislusneho
# objektoveho souboru.
%.o:    %.c
        $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@

10. Výsledky vypsané druhým demonstračním příkladem

Podívejme se nyní na výstup, který získáme po spuštění druhého demonstračního příkladu na jednodeskovém mikropočítači Raspberry Pi. Tento výstup by měl vypadat následovně:

EGL has 28 configurations available
Configuration  R   G   B   A   bpp
  0            8   8   8   8   32
  1            8   8   8   x   24
  2            8   8   8   8   32
  3            8   8   8   x   24
  4            8   8   8   8   32
  5            8   8   8   x   24
  6            8   8   8   8   32
  7            8   8   8   x   24
  8            8   8   8   8   32
  9            8   8   8   x   24
 10            8   8   8   8   32
 11            8   8   8   x   24
 12            8   8   8   8   32
 13            8   8   8   x   24
 14            8   8   8   8   32
 15            8   8   8   x   24
 16            5   6   5   x   16
 17            5   6   5   x   16
 18            5   6   5   x   16
 19            5   6   5   x   16
 20            5   6   5   x   16
 21            5   6   5   x   16
 22            5   6   5   x   16
 23            5   6   5   x   16
 24            8   8   8   8   32
 25            8   8   8   x   24
 26            5   6   5   x   16
 27            5   6   5   x   16
initialize_egl OK
finalize_egl OK

Můžeme zde rozeznat tři skupiny konfigurací:

  1. Framebuffer s bitovou hloubkou 16bpp bez alfa kanálu (hi-color).
  2. Framebuffer s bitovou hloubkou 24bpp bez alfa kanálu (true color).
  3. Framebuffer s bitovou hloubkou 32bpp s alfa kanálem (true color).

11. Informace o Z-bufferu, stencil bufferu a o možnosti navázání barvových bufferů na textury

Na výpisu uvedeném v předchozí kapitole si povšimněte toho, že některé řádky popisují (alespoň zdánlivě) stejnou konfiguraci framebufferu. To není chyba v programu ani chyba v knihovně EGL, protože tyto zdánlivé duplicity jsou způsobeny tím, že prozatím nezískáváme všechny důležité informace o tom, jaké formáty framebufferu jsou dostupné. Pojďme si tedy naše znalosti rozšířit. Již dokážeme načíst a zpracovat všechny důležité informace o barvovém bufferu (RGB) i o případném alfa kanálu. Dále nás může zajímat informace o paměti hloubky neboli Z-bufferu (to v případě 3D grafiky, nikoli u OpenVG). U některých aplikací taktéž využijeme takzvaný stencil buffer, který lze použít pro implementaci některých vizualizačních algoritmů, například pro výpočty stínů apod. Rendering lze navázat i na textury, což je poslední zajímavá a užitečná informace (více viz příště). Tyto informace lze opět velmi snadno přečíst a zobrazit:

#define yes_no(x) ((x)==EGL_TRUE ? "yes":"no ")
 
int depth, stencil;
int bind_to_rgb, bind_to_rgba;
 
eglGetConfigAttrib(display, *config, EGL_DEPTH_SIZE, &depth);
eglGetConfigAttrib(display, *config, EGL_STENCIL_SIZE, &stencil);
 
eglGetConfigAttrib(display, *config,  EGL_BIND_TO_TEXTURE_RGB,  &bind_to_rgb);
eglGetConfigAttrib(display, *config,  EGL_BIND_TO_TEXTURE_RGBA, &bind_to_rgba);
 
printf("%1d   %1d   %1d   %1d   %2d     %2d      %2d      %s  %s\n",
        red, green, blue, alpha, buffer,
        depth, stencil,
        yes_no(bind_to_rgb),
        yes_no(bind_to_rgba));

12. Třetí demonstrační příklad – výpis podrobnějších informací o konfiguraci framebufferu

Ve třetím demonstračním příkladu se po inicializaci knihovny EGL zjistí základní i podrobnější informace o všech dostupných konfiguracích framebufferu. Vzhledem k tomu, že je struktura tohoto příkladu prakticky shodná s příkladem předchozím, se můžeme přímo podívat na jeho zdrojový kód:

/* OpenVG (nejenom) na Raspberry Pi - treti demonstracni priklad */
 
#include <stdio.h>
 
#include <VG/openvg.h>
#include <VG/vgu.h>
#include <EGL/egl.h>
#include <bcm_host.h>
 
 
 
/*
 * Datova struktura obsahujici cely stav EGL "sezeni".
 */
typedef struct
{
    uint32_t screen_width;
    uint32_t screen_height;
 
    uint32_t window_x;
    uint32_t window_y;
    int32_t  window_width;
    int32_t  window_height;
 
    EGLDisplay display;
    EGLSurface surface;
    EGLContext context;
    EGLConfig  config;
} EGL_STATE_T;
 
 
 
/*
 * Vypis konfigurace displeje nabizene pres EGL
 */
void print_egl_configuration(EGLDisplay display, EGLConfig *config)
{
#define yes_no(x) ((x)==EGL_TRUE ? "yes":"no ")
 
    int red, green, blue, alpha, buffer;
    int depth, stencil;
    int bind_to_rgb, bind_to_rgba;
 
    eglGetConfigAttrib(display, *config, EGL_RED_SIZE, &red);
    eglGetConfigAttrib(display, *config, EGL_GREEN_SIZE, &green);
    eglGetConfigAttrib(display, *config, EGL_BLUE_SIZE, &blue);
    eglGetConfigAttrib(display, *config, EGL_ALPHA_SIZE, &alpha);
    eglGetConfigAttrib(display, *config, EGL_BUFFER_SIZE, &buffer);
    eglGetConfigAttrib(display, *config, EGL_DEPTH_SIZE, &depth);
    eglGetConfigAttrib(display, *config, EGL_STENCIL_SIZE, &stencil);
 
    eglGetConfigAttrib(display, *config,  EGL_BIND_TO_TEXTURE_RGB,  &bind_to_rgb);
    eglGetConfigAttrib(display, *config,  EGL_BIND_TO_TEXTURE_RGBA, &bind_to_rgba);
 
    printf("%1d   %1d   %1d   %1d   %2d     %2d      %2d      %s  %s\n",
            red, green, blue, alpha, buffer,
            depth, stencil,
            yes_no(bind_to_rgb),
            yes_no(bind_to_rgba));
}
 
 
 
/*
 * Inicializace EGL.
 */
void initialize_egl(EGL_STATE_T *state)
{
    EGLBoolean result;
    EGLint     configurations_count;
    EGLConfig *all_configurations;
 
    /* nutne pro RPi */
    bcm_host_init();
 
    /* pro jistotu vymazeme datovou strukturu nesouci stav EGL */
    memset(state, 0, sizeof(*state));
 
    /* propojeni na vychozi displej */
    state->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
 
    /* inicializace displeje */
    result = eglInitialize(state->display, NULL, NULL);
 
    /* kontrola, zda inicializace probehla v poradku */
    if (result == EGL_FALSE) {
        puts("EGL init failed");
        exit(1);
    }
 
    /* precteni poctu konfiguraci dostupnych pres EGL */
    eglGetConfigs(state->display, NULL, 0, &configurations_count);
    printf("EGL has %d configurations available\n", configurations_count);
 
    /* nacteni vsech konfiguraci do pripraveneho pole */
    all_configurations = malloc(configurations_count * sizeof(*all_configurations));
    eglGetConfigs(state->display, all_configurations, configurations_count, &configurations_count);
 
    puts("Configuration  R   G   B   A   bpp   depth stencil bind RGB/RGBA");
    /* postupny vypis vsech konfiguraci */
    int i;
    for (i = 0; i < configurations_count; i++) {
        printf("%3d            ", i);
        print_egl_configuration(state->display, &all_configurations[i]);
    }
    free(all_configurations);
}
 
 
 
/*
 * Ukonceni prace s EGL.
 */
void finalize_egl(EGL_STATE_T *state)
{
    /* nyni jsou tyto kroky prozatim zbytecne, v dalsich prikladech se vsak budou hodit */
    eglSwapBuffers(state->display, state->surface);
    eglMakeCurrent(state->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    eglDestroySurface(state->display, state->surface);
    eglDestroyContext(state->display, state->context);
    eglTerminate(state->display);
}
 
 
 
/*
 * Vstupni bod do programu.
 */
int main(int argc, char *argv[])
{
    EGL_STATE_T egl_state;
 
    initialize_egl(&egl_state);
    puts("initialize_egl OK");
 
    finalize_egl(&egl_state);
    puts("finalize_egl OK");
 
    return 0;
}

Soubor Makefile použitý pro překlad a slinkování třetího příkladu má tento obsah:

# Makefile pro preklad tretiho prikladu ukazujiciho
# praci s OpenVG a EGL.
 
# Parametry prekladace.
CFLAGS=-Wall
 
# Dalsi parametry prekladace, zde adresare, kde se maji 
# hledat hlavickove soubory.
INCLUDES=-I/opt/vc/include/ -I/opt/vc/include/interface/vcos/pthreads -I/opt/vc/include/interface/vmcs_host/linux
 
# Parametry linkeru.
LDFLAGS=-L/opt/vc/lib/ -lGLESv2 -lEGL -lopenmaxil -lbcm_host -lvcos -lvchiq_arm -lpthread -lrt -lm
 
PROGNAME=example3
 
# Vychozi pravidlo pro vytvoreni vysledne spustitelne aplikace.
all:    $(PROGNAME)
 
clean:
        rm -f *.o
        rm -f $(PROGNAME)
 
# Pravidlo pro slinkovani vsech objektovych souboru a vytvoreni
# vysledne spustitelne aplikace.
$(PROGNAME):    $(PROGNAME).o
        $(CC) -o $@ $(LDFLAGS) $<
 
# Pravidlo pro preklad kazdeho zdrojoveho souboru do prislusneho
# objektoveho souboru.
%.o:    %.c
        $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@

13. Výsledky vypsané třetím demonstračním příkladem

Podívejme se nyní na výstup, který získáme po spuštění třetího demonstračního příkladu na jednodeskovém mikropočítači Raspberry Pi. Tento výstup by měl vypadat následovně:

EGL has 28 configurations available
Configuration  R   G   B   A   bpp   depth stencil bind RGB/RGBA
  0            8   8   8   8   32     24       8      no   yes
  1            8   8   8   0   24     24       8      yes  yes
  2            8   8   8   8   32     24       0      no   yes
  3            8   8   8   0   24     24       0      yes  yes
  4            8   8   8   8   32      0       8      no   yes
  5            8   8   8   0   24      0       8      yes  yes
  6            8   8   8   8   32      0       0      no   yes
  7            8   8   8   0   24      0       0      yes  yes
  8            8   8   8   8   32     24       8      no   no
  9            8   8   8   0   24     24       8      no   no
 10            8   8   8   8   32     24       0      no   no
 11            8   8   8   0   24     24       0      no   no
 12            8   8   8   8   32      0       8      no   no
 13            8   8   8   0   24      0       8      no   no
 14            8   8   8   8   32      0       0      no   no
 15            8   8   8   0   24      0       0      no   no
 16            5   6   5   0   16     24       8      yes  yes
 17            5   6   5   0   16     24       0      yes  yes
 18            5   6   5   0   16      0       8      yes  yes
 19            5   6   5   0   16      0       0      yes  yes
 20            5   6   5   0   16     24       8      no   no
 21            5   6   5   0   16     24       0      no   no
 22            5   6   5   0   16      0       8      no   no
 23            5   6   5   0   16      0       0      no   no
 24            8   8   8   8   32      0       0      no   yes
 25            8   8   8   0   24      0       0      yes  yes
 26            5   6   5   0   16      0       0      yes  yes
 27            5   6   5   0   16     16       0      yes  yes
initialize_egl OK
finalize_egl OK

Získané informace jsou již mnohem zajímavější, protože původní tři skupiny:

  1. Framebuffer s bitovou hloubkou 16bpp bez alfa kanálu (hi-color).
  2. Framebuffer s bitovou hloubkou 24bpp bez alfa kanálu (true color).
  3. Framebuffer s bitovou hloubkou 32bpp s alfa kanálem (true color).

se nyní rozpadají na další podskupiny:

  1. Bez paměti hloubky (Z-bufferu).
  2. S pamětí hloubky (Z-bufferem), 24bpp (resp. přesněji 24 bits per fragment).
  1. Bez stencil bufferu.
  2. Se stencil bufferem (ten má hloubku 8 bitů, což lze využít při implementaci čítačů atd., nejenom pro čistě bitovou masku).

14. Obsah následující části seriálu

Dnešní článek byl pravděpodobně pro některé čtenáře dosti nezáživný, protože jsme se v něm zabývali pouze problematikou řešenou knihovnou EGL, tj. relativně nízkoúrovňovými věcmi. Nicméně i tuto část je dobré pochopit a nejenom bez rozmyslu použít již hotové knihovny tvořící uživatelsky přívětivější vrstvu nad EGL. Příště si však již ukážeme, jakým způsobem je možné prakticky využít knihovnu OpenVG pro tvorbu dvoudimenzionálních scén složených jak z rastrových obrázků, tak i z různých 2D primitiv (úsečka, obdélník, Bézierova křivka, kružnice, elipsa apod.). Zájemci se mohou – prozatím ovšem bez dalšího popisu – podívat na demonstrační příklad, kterým se budeme zabývat příště. Tento příklad je dostupný na adrese https://github.com/tisnik/pre­sentations/tree/master/open­vg/example4 (zdrojový kód byl opět odladěn na Raspberry Pi s Raspbiannem).

15. Repositář s demonstračními příklady

Všechny tři demonstrační příklady, které jsme si v dnešním článku popsali, byly uloženy do Git repositáře dostupného na adrese https://github.com/tisnik/pre­sentations. V tabulce zobrazené pod tímto odstavcem naleznete na zdrojové kódy všech tří zmíněných demonstračních příkladů přímé odkazy:

Pro zjednodušení překladu je ke každému příkladu přiložen i příslušný Makefile.

16. Odkazy na Internetu

  1. EGL quick reference card
    https://www.khronos.org/files/egl-1–4-quick-reference-card.pdf
  2. EGL Reference Pages Index
    https://www.khronos.org/re­gistry/egl/sdk/docs/man/html/in­dexflat.php
  3. Funkce eglInitialize
    https://www.khronos.org/re­gistry/egl/sdk/docs/man/html/e­glInitialize.xhtml
  4. Funkce eglGetDisplay
    https://www.khronos.org/re­gistry/egl/sdk/docs/man/html/e­glGetDisplay.xhtml
  5. Funkce eglGetConfigs
    https://www.khronos.org/re­gistry/egl/sdk/docs/man/html/e­glGetConfigs.xhtml
  6. Funkce eglGetConfigAttrib
    https://www.khronos.org/re­gistry/egl/sdk/docs/man/html/e­glGetConfigAttrib.xhtml
  7. Funkce eglDestroySurface
    https://www.khronos.org/re­gistry/egl/sdk/docs/man/html/e­glDestroySurface.xhtml
  8. Funkce eglDestroyContext
    https://www.khronos.org/re­gistry/egl/sdk/docs/man/html/e­glDestroyContext.xhtml
  9. Funkce eglTerminate
    https://www.khronos.org/re­gistry/egl/sdk/docs/man/html/e­glTerminate.xhtml
  10. Khronos Native Platform Graphics Interface
    https://www.khronos.org/re­gistry/egl/specs/eglspec.1­.4.pdf
  11. Khronos Group
    https://www.khronos.org/
  12. Khronos Group (Wikipedia)
    https://en.wikipedia.org/wi­ki/Khronos_Group
  13. Raspberry Pi VideoCore APIs
    http://elinux.org/Raspberry_Pi_Vi­deoCore_APIs
  14. Programming AudioVideo on the Raspberry Pi GPU
    https://jan.newmarch.name/RPi/in­dex.html
  15. The Standard for Vector Graphics Acceleration
    https://www.khronos.org/openvg/
  16. OpenVG (Wikipedia)
    https://en.wikipedia.org/wiki/OpenVG
  17. OpenVG Quick Reference Card
    https://www.khronos.org/files/openvg-quick-reference-card.pdf
  18. OpenVG on the Raspberry Pi
    http://mindchunk.blogspot­.cz/2012/09/openvg-on-raspberry-pi.html
  19. ShivaVG: open-source ANSI C OpenVG
    http://ivanleben.blogspot­.cz/2007/07/shivavg-open-source-ansi-c-openvg.html
  20. Testbed for exploring OpenVG on the Raspberry Pi
    https://github.com/ajstarks/openvg
  21. Programovací jazyky a knihovny určené pro výuku základů počítačové grafiky: knihovna Pygame
    http://mojefedora.cz/programovaci-jazyky-a-knihovny-urcene-pro-vyuku-zakladu-pocitacove-grafiky-knihovna-pygame/
  22. Programovací jazyky a knihovny určené pro výuku základů počítačové grafiky: knihovna Pygame prakticky
    http://mojefedora.cz/programovaci-jazyky-a-knihovny-urcene-pro-vyuku-zakladu-pocitacove-grafiky-knihovna-pygame-prakticky/
  23. Programovací jazyky a knihovny určené pro výuku základů počítačové grafiky: práce s bitmapami a TrueType fonty
    http://mojefedora.cz/programovaci-jazyky-a-knihovny-urcene-pro-vyuku-zakladu-pocitacove-grafiky-prace-s-bitmapami-a-truetype-fonty/
  24. Programovací jazyky a knihovny určené pro výuku základů počítačové grafiky: sprity v knihovně Pygame
    http://mojefedora.cz/programovaci-jazyky-a-knihovny-urcene-pro-vyuku-zakladu-pocitacove-grafiky-sprity-v-knihovne-pygame/
  25. Programovací jazyky a knihovny určené pro výuku základů počítačové grafiky: detekce kolize spritů
    http://mojefedora.cz/programovaci-jazyky-a-knihovny-urcene-pro-vyuku-zakladu-pocitacove-grafiky-detekce-kolize-spritu/
  26. Seriál Grafické karty a grafické akcelerátory
    http://www.root.cz/serialy/graficke-karty-a-graficke-akceleratory/
  27. Grafika na osmibitových počítačích firmy Sinclair II
    http://www.root.cz/clanky/grafika-na-osmibitovych-pocitacich-firmy-sinclair-ii/
  28. Xiaolin_Wu's Line Algorithm
    https://en.wikipedia.org/wi­ki/Xiaolin_Wu's_line_algo­rithm
  29. Grafické čipy v osmibitových počítačích Atari
    http://www.root.cz/clanky/graficke-cipy-v-osmibitovych-pocitacich-atari/
  30. Osmibitové počítače Commodore a čip VIC-II
    http://www.root.cz/clanky/osmibitove-pocitace-commodore-a-cip-vic-ii/
  31. Grafika na osmibitových počítačích firmy Apple
    http://www.root.cz/clanky/grafika-na-osmibitovych-pocitacich-firmy-apple/
  32. Počátky grafiky na PC: grafické karty CGA a Hercules
    http://www.root.cz/clanky/pocatky-grafiky-na-pc-graficke-karty-cga-a-hercules/
  33. Karta EGA: první použitelná barevná grafika na PC
    http://www.root.cz/clanky/karta-ega-prvni-pouzitelna-barevna-grafika-na-pc/
  34. Grafické karty MCGA a VGA
    http://www.root.cz/clanky/graficke-karty-mcga-a-vga/
  35. Grafický subsystém počítačů Amiga
    http://www.root.cz/clanky/graficky-subsystem-pocitacu-amiga/
  36. Grafický subsystém počítačů Amiga II
    http://www.root.cz/clanky/graficky-subsystem-pocitacu-amiga-ii/
  37. Raspberry Pi pages
    https://www.raspberrypi.org/
  38. BCM2835 registers
    http://elinux.org/BCM2835_registers
  39. VideoCore (archiv stránek společnosti Alphamosaic)
    http://web.archive.org/web/20030209213838/www­.alphamosaic.com/videocore/
  40. VideoCore (Wikipedia)
    https://en.wikipedia.org/wi­ki/Videocore
  41. RPi lessons: Lesson 6 Screen01
    http://www.cl.cam.ac.uk/pro­jects/raspberrypi/tutorial­s/os/screen01.html
  42. Raspberry Pi forum: Bare metal
    https://www.raspberrypi.or­g/forums/viewforum.php?f=72
  43. C library for Broadcom BCM 2835 as used in Raspberry Pi
    http://www.airspayce.com/mi­kem/bcm2835/
  44. Raspberry Pi Hardware Components
    http://elinux.org/RPi_Har­dware#Components
  45. (Linux) Framebuffer
    http://wiki.linuxquestion­s.org/wiki/Framebuffer
  46. (Linux) Framebuffer HOWTO
    http://tldp.org/HOWTO/Framebuffer-HOWTO/
  47. Linux framebuffer (Wikipedia)
    https://en.wikipedia.org/wi­ki/Linux_framebuffer
  48. RPi Framebuffer
    http://elinux.org/RPi_Framebuffer
  49. HOWTO: Boot your Raspberry Pi into a fullscreen browser kiosk
    http://blogs.wcode.org/2013/09/howto-boot-your-raspberry-pi-into-a-fullscreen-browser-kiosk/
  50. Zdrojový kód fb.c pro RPI
    https://github.com/jncronin/rpi-boot/blob/master/fb.c
  51. RPiconfig
    http://elinux.org/RPi_config.txt
  52. Mailbox framebuffer interface
    https://github.com/raspbe­rrypi/firmware/wiki/Mailbox-framebuffer-interface
  53. Seriál Grafické formáty
    http://www.root.cz/serialy/graficke-formaty/
Našli jste v článku chybu?
Měšec.cz: Co s reklamací, když e-shop krachuje?

Co s reklamací, když e-shop krachuje?

Vitalia.cz: Za její cukrovkou stojí rodiče

Za její cukrovkou stojí rodiče

Měšec.cz: TEST: Vyzkoušeli jsme pražské taxikáře

TEST: Vyzkoušeli jsme pražské taxikáře

Měšec.cz: 10 změn novely zákoníku práce

10 změn novely zákoníku práce

Měšec.cz: Ceny PHM v Evropě. Finty na úspory

Ceny PHM v Evropě. Finty na úspory

Vitalia.cz: 9 potravin, které nesmí chybět v jídelníčku těhotné

9 potravin, které nesmí chybět v jídelníčku těhotné

Podnikatel.cz: Chce dodávat chlebíčky. Jaká živnost je třeba?

Chce dodávat chlebíčky. Jaká živnost je třeba?

Podnikatel.cz: OSA zdraží, ale taky přidá nový poplatek

OSA zdraží, ale taky přidá nový poplatek

Lupa.cz: Nechcete datacentrum? Jsou na prodej

Nechcete datacentrum? Jsou na prodej

DigiZone.cz: Pevnost Boyard v září a česká

Pevnost Boyard v září a česká

Podnikatel.cz: Kauza z Vinohrad pokračuje. Policie se omlouvá

Kauza z Vinohrad pokračuje. Policie se omlouvá

Lupa.cz: Kdo vykrádá LinkedIn? Zjistit to má soud

Kdo vykrádá LinkedIn? Zjistit to má soud

Lupa.cz: Elektronika tajemství zbavená. Jak s ní začít?

Elektronika tajemství zbavená. Jak s ní začít?

120na80.cz: Lepší poporodní sexuální život? Žádný problém

Lepší poporodní sexuální život? Žádný problém

Lupa.cz: Co vzal čas: internetové kavárny a herny

Co vzal čas: internetové kavárny a herny

Měšec.cz: Na návštěvě na exekutorském úřadě

Na návštěvě na exekutorském úřadě

120na80.cz: Kam umístit silikony?

Kam umístit silikony?

Měšec.cz: Udali ho na nelegální software a přišla Policie

Udali ho na nelegální software a přišla Policie

Měšec.cz: Co když na dovolené přijdete o kartu?

Co když na dovolené přijdete o kartu?

120na80.cz: Víte, co je svobodná menstruace?

Víte, co je svobodná menstruace?