Pohled pod kapotu JVM – výkonnost aplikací vytvořených s využitím SDLJava v porovnání s nativními aplikacemi

Pavel Tišnovský 13. 5. 2014

V dnešní části seriálu o JVM i o jazyku Java dokončíme popis multimediální knihovny SDLJava. Řekneme si o některých základních pravidlech pro tvorbu efektivních aplikací a následně porovnáme výkonnost dvou prakticky totožných programů, z nichž jeden je napsán v kombinaci C+SDL a druhý v kombinaci Java+SDLJava.

Obsah

1. Pohled pod kapotu JVM – výkonnost aplikací vytvořených s využitím SDLJava v porovnání s nativními aplikacemi

2. Problematika vytváření nových objektů při běhu aplikace

3. Přímý přístup do paměti vs. použití třídy ByteBuffer

4. Porovnání dvou metod přístupu do obrazové paměti

5. Demonstrační příklad SDLTest69 – využití knihovny SDL při renderingu

6. Demonstrační příklad SDLTest70 – využití knihovny SDLJava při renderingu

7. Porovnání času běhu obou demonstračních příkladů

8. Repositář se zdrojovými kódy obou dnešních demonstračních příkladů

9. Odkazy na Internetu

1. Pohled pod kapotu JVM – výkonnost aplikací vytvořených s využitím SDLJava v porovnání s nativními aplikacemi

V dnešní části seriálu o programovacím jazyce Java i o virtuálním stroji tohoto jazyka dokončíme popis multimediální knihovny SDLJava. Nejprve se zmíníme o některých základních pravidlech, jejichž dodržování povede k tvorbě efektivně naprogramovaných aplikací, které například nebudou trpět špatnými odezvami či vysokými paměťovými nároky. Ve druhé části článku bude porovnána výkonnost dvou programů provádějících výpočet a vykreslení animace systémů iterovaných funkcí (IFS). První z těchto programů je napsán v programovacím jazyku C s využitím knihovny SDL, zatímco druhý (funkčně totožný) program je napsán v Javě a při svém běhu využívá možnosti knihovny SDLJava (což je, jak již víme, jen poměrně úzká mezivrstva mezi Javou a nativní knihovnou SDL).

Obrázek 1: IFS vykreslený demonstračními příklady.

2. Problematika vytváření nových objektů při běhu aplikace

Při tvorbě multimediálních aplikací (samozřejmě včetně počítačových her) v programovacím jazyku Java většinou vývojáři narazí na několik problémů, které částečně souvisí s vlastnostmi Javy, s architekturou JVM popř. s návrhem základních knihoven. Tvorba multimediálních programů s využitím AWT či Swingu je sice možná, mnohdy se však nejedná o tu nejefektivnější možnost – právě z tohoto důvodu vznikla knihovna SDLJava, která dává Javovským programátorům možnost poměrně snadno a elegantně přistupovat k funkcím a datovým strukturám knihovny SDL i dalších podpůrných knihoven (SDL_Image atd.). S využitím SDLJava a současným obejitím AWT a Swingu lze skutečně vytvořit například hru, jejíž odezvy i celkový výkon mohou být srovnatelné s podobně navrženou aplikací naprogramovanou v C či C++ (či jiném jazyku kompilovaném přímo do nativního strojového kódu), ovšem je zapotřebí dodržet několik jednoduchých pravidel.

Obrázek 2: Další IFS vykreslený demonstračními příklady.

Především je nutné se vyvarovat toho, aby neustále docházelo k tvorbě nových objektů v hlavní programové smyčce, která je většinou základem „herního enginu“. Většinou se nelze tvorbě nových objektů zcela vyhnout, ovšem díky návrhu SDLJava je počet nově vytvářených objektů skutečně minimalizován, zejména v porovnání s knihovnou AWT/Swing, v níž vznikají nové objekty i skrytě, tj. zavoláním některých metod již existujících instancí tříd. Základ „herního enginu“, přesněji řečeno jeho grafické části, je většinou postaven na sadě bitmap reprezentovaných objekty typu SDLSurface, při jejichž vykreslování do framebufferu se používá datová struktura SDLRect. Bitmapy typicky existují po celou dobu běhu aplikace, takže zde k tvorbě nových objektů nedochází a v případě datové struktury SDLRect může být vhodné znovu použít již jednou vytvořený objekt tohoto typu, než například vytvářet SDLRect na úrovni lokální proměnné či dokonce uvnitř programové smyčky.

Obrázek 3: Třetí IFS vykreslený demonstračními příklady.

Vytváření nových objektů je problematické z toho důvodu, že se po zaplnění té části haldy (heapu), která se jmenuje eden space spustí správce paměti (GC), jenž sice běží v samostatném vláknu či v několika samostatných vláknech, ale minimálně v době skenování obsazení haldy je nutné pozastavit i vlákna samotné aplikace, což je v případě her či dalších multimediálních programů samozřejmě nepříjemné. Tento problém není možné obejít ani prostým zvětšením velikosti haldy, protože by ve skutečnosti mohl být výsledek ještě horší, protože by se zvětšil i počet objektů, které správce paměti bude muset při své činnosti přesunout z jednoho regionu na haldě do druhého regionu (a následně upravit reference na tyto objekty).

Obrázek 4: Jedním ze základních nástrojů použitelných i při tvorbě her, je JConsole dodávaná přímo s JDK.

Sledovat práci správce paměti lze snadno i s využitím volby předané JVM při jejím startu:

java -verbose:gc Game

Výstup může vypadat následovně:

0.109: [GC 896K->118K(5056K), 0.0026554 secs]
0.115: [GC 1014K->123K(5056K), 0.0010161 secs]
0.119: [GC 1016K->120K(5056K), 0.0004892 secs]
...                    ...
...                    ...
...                    ...
2.491: [GC 2208K->1540K(5056K), 0.0003350 secs]
2.493: [GC 2399K->1635K(5056K), 0.0002609 secs]
2.495: [GC 2495K->1826K(5056K), 0.0003830 secs]
2.497: [GC 2686K->1921K(5056K), 0.0002724 secs]
2.499: [GC 2782K->2112K(5056K), 0.0003674 secs]
2.501: [GC 2973K->2208K(5056K), 0.0002763 secs]
2.502: [GC 3069K->2398K(5056K), 0.0003746 secs]
2.504: [GC 3260K->2494K(5056K), 0.0002911 secs]
2.506: [Full GC 2687K->211K(5056K), 0.0163401 secs]

3. Přímý přístup do paměti vs. použití třídy ByteBuffer

S bitmapami, přesněji řečeno s objekty typu SDLSurface, lze provádět několik operací. Základní operací je operace typu BitBLT, tj. přesun celé bitmapy či její části na bitmapu jinou, popř. současná aplikace maskování či aplikace alfa blendingu, to vše v závislosti na nastavených režimech. Ovšem v bitmapě je mnohdy nutné modifikovat barvy jednotlivých pixelů. Pro tuto činnost nabízí nativní knihovna SDL možnost takzvaného uzamčení bitmapy a získání ukazatele do oblasti paměti, kde jsou uloženy pixely bitmapy. V případě knihovny SDLJava tato funkcionalita – celkem pochopitelně – nemohla být implementována, takže se při uzamčení bitmapy vrátí nikoli ukazatel na paměť s pixely, ale objekt typu ByteBuffer, který nabízí několik metod pro modifikaci hodnot pixelů. Tato operace se svou efektivitou může přiblížit přímé manipulaci s ukazateli, což je u mnoha multimediálních aplikací velmi důležité.

Obrázek 5: Jedním ze základních nástrojů použitelných i při tvorbě her, je JConsole dodávaná přímo s JDK.

4. Porovnání dvou metod přístupu do obrazové paměti

Podívejme se nyní na způsob přístupu k jednotlivým pixelům bitmapy. Nejprve je vypsána část aplikace vytvořená v programovacím jazyku C, která získá ukazatel na první pixel bitmapy a uloží ho do proměnné pixel. Následně je již možné v programové smyčce jednoduše zapisovat nové barvy pixelů a zvyšovat hodnotu ukazatele, tj. přesunovat se na další pixel (zde se předpokládá formát RGB, tj. situace, kdy je každý pixel reprezentován trojicí bajtů a obrazové řádky nejsou zarovnány):

/* primy pristup k pixelum */
Uint8 *pixel = (Uint8 *)pixmap->pixels;
 
/* rozmery bitmapy */
const int width = pixmap->w;
const int height = pixmap->h;
 
/* vlastni rendering */
int x, y;
 
for (y = 0; y < height; y++)
{
    for (x = 0; x < width; x++)
    {
        int color = compute_color(x, y);
        *pixel++ = color;
        *pixel++ = color;
        *pixel++ = color;
    }
}

V případě použití programovacího jazyka Java a knihovny SDLJava se namísto přístupu k datové struktuře bitmapy musí použít metoda SDLSurface.getPixelData() vracející instanci třídy java.nio.ByteBuffer. Namísto přímého přístupu do paměti/bufferu přes ukazatel se zde volá metoda put() existující v několika variantách. V následujícím úryvku kódu je ukázána varianta, v níž se vždy specifikuje index zapisovaného bajtu, což z implementačního hlediska připomíná práci s jednorozměrným polem:

/* primy pristup k pixelum */
java.nio.ByteBuffer pixels = pixmap.getPixelData();
 
/* rozmery bitmapy */
final int width = pixmap.getWidth();
final int height = pixmap.getHeight();
 
/* vlastni rendering */
int index = 0;
for (int y = 0; y < height; y++)
{
    for (int x = 0; x < width; x++)
    {
        int color = compute_color(x, y);
        // barvy pixelu se mohou vyplnit pres metody nabizene tridou ByteBuffer
        pixels.put(index++, (byte)color);
        pixels.put(index++, (byte)color);
        pixels.put(index++, (byte)color);
    }
}

5. Demonstrační příklad SDLTest69 – využití knihovny SDL při renderingu

Pro porovnání způsobu práce s nativní knihovnou SDL a její mezivrstvou SDLJava byla vytvořena dvojice aplikací s prakticky shodným chováním. Obě aplikace nejprve otevřou okno (popř. nastaví vhodný celoobrazovkový grafický režim) a posléze do něj vykreslí animaci vypočtenou s využitím systémů iterovaných funkcí (IFS) a interpolací mezi jednotlivými IFS. Při výpočtu se navíc provádí normalizace obrazu (samotný obraz je vlastně histogramem, kde úroveň černé odpovídá počtu „zásahů“ každého pixelu body tvořícími IFS). Aplikace je založena na několika operacích – aplikacích transformační matice (operace nad čísly uloženými ve formátu float), čtení a zápis do dvourozměrného pole s prvky typu int, zápis barev pixelů do bitmapy a konečně přesun bitmapy do framebufferu. V této kapitole je uvedena varianta aplikace naprogramovaná v jazyku C s využitím knihovny SDL:

/*
 * Vyuziti knihovny SDL pri renderingu.
 *
 * Pavel Tisnovsky 2014
 *
 * Preklad;
 * gcc -ansi -Wall -pedantic -O9 -ffast-math sdl_test.c -lSDLmain -lSDL
 */
 
#include <stdio.h>
#include <math.h>
#include <SDL/SDL.h>
 
#define WINDOW_WIDTH  640
#define WINDOW_HEIGHT 480
#define IMAGE_WIDTH   320
#define IMAGE_HEIGHT  240
 
/*
 * Ukazatel na data predstavujici framebuffer.
 */
SDL_Surface *screen;
 
/*
 * Ukazatel na bitmapu, do ktere se provadi rendering.
 */
SDL_Surface *pixmap;
 
/*
 * Pouzito pri renderingu - celkovy pocet "zasahu" jednotlivych pixelu.
 */
int histogram[IMAGE_HEIGHT][IMAGE_WIDTH];
 
/*
 * Celkovy pocet pixelu pri vypoctu.
 */
const int IFS_PIXELS = IMAGE_WIDTH*IMAGE_HEIGHT;
 
/*
 * Transformacni matice (+koeficient pravdepodobnosti) jednotlivych IFS.
 */
static float data[][7]={
    { 0.500000, 0.000000, 0.000000, 0.500000,-2.563477,-0.000003, 0.333333},
    { 0.500000, 0.000000, 0.000000, 0.500000, 2.436544,-0.000003, 0.333333},
    { 0.000000,-0.500000, 0.500000, 0.000000, 4.873085, 7.563492, 0.333333},
    { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
    { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
 
    { 0.307692,-0.531469,-0.461538,-0.293706, 5.401953, 8.655175, 0.400000},
    { 0.307692,-0.076923, 0.153846,-0.447552,-1.295248, 4.152990, 0.150000},
    { 0.000000, 0.545455, 0.692308,-0.195804,-4.893637, 7.269794, 0.450000},
    { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
    { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
 
    { 0.696970,-0.481061,-0.393939,-0.662879, 2.147003,10.310288, 0.747826},
    { 0.090909,-0.443182, 0.515152,-0.094697, 4.286558, 2.925762, 0.252174},
    { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
    { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
    { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
 
    { 0.824074, 0.281482,-0.212346, 0.864198,-1.882290,-0.110607, 0.787473},
    { 0.088272, 0.520988,-0.463889,-0.377778, 0.785360, 8.095795, 0.212527},
    { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
    { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
    { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
 
    { 0.824074, 0.281481,-0.212346, 0.864197,-1.772710, 0.137795, 0.771268},
    {-0.138580, 0.283951,-0.670062,-0.279012, 2.930991, 7.338924, 0.228732},
    { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
    { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
    { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
 
    { 0.870370, 0.074074,-0.115741, 0.851852,-1.278016, 0.070331, 0.798030},
    {-0.162037,-0.407407, 0.495370, 0.074074, 6.835726, 5.799174, 0.201970},
    { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
    { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
    { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
 
    { 0.850000, 0.040000,-0.040000, 0.850000, 0.000000, 1.600000, 0.850000},
    { 0.200000,-0.260000, 0.230000, 0.220000, 0.000000, 1.600000, 0.070000},
    {-0.150000, 0.280000, 0.260000, 0.240000, 0.000000, 0.440000, 0.070000},
    { 0.000000, 0.000000, 0.000000, 0.160000, 0.000000, 0.000000, 0.010000},
    { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
 
    { 0.307692, 0.000000, 0.000000, 0.294118, 4.119164, 1.604278, 0.151515},
    { 0.192308,-0.205882, 0.653846, 0.088235,-0.688840, 5.978916, 0.253788},
    { 0.192308, 0.205882,-0.653846, 0.088235, 0.668580, 5.962514, 0.253788},
    { 0.307692, 0.000000, 0.000000, 0.294118,-4.136530, 1.604278, 0.151515},
    { 0.384615, 0.000000, 0.000000,-0.294118,-0.007718, 2.941176, 1.000000},
 
    { 0.787879,-0.424242, 0.242424, 0.859848, 1.758647, 1.408065, 0.895652},
    {-0.121212, 0.257576, 0.151515, 0.053030,-6.721654, 1.377236, 0.052174},
    { 0.181818,-0.136364, 0.090909, 0.181818, 6.086107, 1.568035, 0.052174},
    { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
    { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
 
    { 0.000000, 0.000000, 0.000000, 0.500000, 0.000000, 0.000000, 0.050000},
    { 0.420000,-0.420000, 0.420000, 0.420000, 0.000000, 0.200000, 0.400000},
    { 0.420000, 0.420000,-0.420000, 0.420000, 0.000000, 0.200000, 0.400000},
    { 0.100000, 0.000000, 0.000000, 0.100000, 0.000000, 0.200000, 0.150000},
    { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
 
    { 0.500000, 0.000000, 0.000000, 0.500000,-0.500000, 0.000000, 0.333333},
    { 0.500000, 0.000000, 0.000000, 0.500000, 0.500000, 0.000000, 0.333333},
    { 0.500000, 0.000000, 0.000000, 0.500000, 0.000000, 0.860000, 0.333334},
    { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
    { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
};
 
/*
 * Inicializace knihovny SDL.
 */
static void init_sdl(void)
{
    if (SDL_Init(SDL_INIT_VIDEO) < 0)
    {
        fprintf(stderr, "Error initializing SDL: %s\n", SDL_GetError());
        exit(1);
    }
#ifdef FULLSCREEN
    screen = SDL_SetVideoMode(WINDOW_WIDTH, WINDOW_HEIGHT, 32, SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_FULLSCREEN | SDL_ANYFORMAT);
#else
    screen = SDL_SetVideoMode(WINDOW_WIDTH, WINDOW_HEIGHT, 32, SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_ANYFORMAT);
#endif
    if (!screen)
    {
        fprintf(stderr, "Error setting video mode: %s\n", SDL_GetError());
        exit(1);
    }
}
 
/*
 * Ukonceni prace programu.
 */
void finalize(void)
{
    SDL_FreeSurface(pixmap);
    SDL_FreeSurface(screen);
    SDL_Quit();
}
 
/*
 * Provedeni operace typu BitBlt (Bit Block Transfer)
 */
void gfx_bitblt(SDL_Surface *surface, const int x, const int y)
{
    SDL_Rect dst_rect;
    dst_rect.x = x;
    dst_rect.y = y;
    SDL_BlitSurface(surface, NULL, screen, &dst_rect);
}
 
/*
 * Prohozeni predniho a zadniho bufferu.
 */
void gfx_flip(void)
{
    SDL_Flip(screen);
}
 
/*
 * Prepocet obrazku s IFS fraktalem.
 */
void recalcIFS(int max_iter, int start_iter, float morph_ratio, int first_ifs, int second_ifs)
{
    const float scale_factor=12.0;
    const float scale_factor_x = pixmap->w / scale_factor;
    const float scale_factor_y = pixmap->h / scale_factor;
    const float xmin=-6.0;
    const float ymin=-1.0;
 
    /* operace deleni je pomala, dokonce i pro float */
    const float rand_max_inv = 1.0 / RAND_MAX;
 
    float x1=0, y1=0, x2, y2;
    int   i, j, k;
    float maxp=0;
    int  *ip;
    Uint8 *pixel = (Uint8 *)pixmap->pixels;
 
    float a[5][7];
 
    /* vypocet vsech peti transformacnich matic na zaklade hodnoty morph_ratio */
    for (j=0; j<5; j++)
    {
        for (i=0; i<7; i++)
        {
            a[j][i]=(1.0-morph_ratio)*data[j+first_ifs*5][i]
                       +(morph_ratio)*data[j+second_ifs*5][i];
        }
    }
 
    /* vlastni vypocet IFS */
    for (i=0; i<max_iter; i++)
    {
        float pp = rand()*rand_max_inv;
        float sum=0;
        for (k=0; sum<=pp; k++)
            sum+=a[k][6];
        k--;
        x2 = x1*a[k][0] + y1*a[k][1] + a[k][4];
        y2 = x1*a[k][2] + y1*a[k][3] + a[k][5];
        x1 = x2;
        y1 = y2;
        if (i > start_iter)
        {
            int x = (int) ((x1 - xmin) * scale_factor_x);
            int y = (int) ((y1 - ymin) * scale_factor_y);
            if (x >= 0 && y >=0 && x < pixmap->w && y < pixmap->h)
            {
                histogram[y][x]++;
            }
        }
    }
 
    /* vypocet maxp pro normalizaci obrazu */
    ip = &histogram[0][0];
    for (i=0; i<IFS_PIXELS; i++)
    {
        if (maxp<*ip) maxp=*ip;
        ip++;
    }
    /* prepocet konstanty pro normalizaci */
    maxp = 255.0 / log(maxp);
 
    /* vlastni rendering */
    ip = &histogram[0][0];
    for (i=0; i<IFS_PIXELS; i++)
    {
        int color = 0xff & (int)(log(*ip)*maxp);
        color = ~color;
        ip++;
        *pixel++ = color;
        *pixel++ = color;
        *pixel++ = color;
    }
}
 
/*
 * Reagovat na zavreni okna aplikace i na klavesy Esc a Q.
 */
int should_we_quit(void)
{
    SDL_Event event;
 
    SDL_PollEvent(&event);
    switch (event.type)
    {
        case SDL_QUIT:
            return 1;
            break;
        case SDL_KEYDOWN:
            switch (event.key.keysym.sym)
            {
                case SDLK_ESCAPE:
                case SDLK_q:
                    return 1;
                    break;
                default:
                    break;
            }
    }
    return 0;
}
 
/*
 * Vlastni animace.
 */
void animation(SDL_Surface *pixmap)
{
    int max_iter=50000;
    int start_iter=100;
    int frames=100;
    int i,j;
 
    /* prvky tohoto pole predstavuji prechody mezi jednotlivymi IFS. */
    int ifs_indexes[]={0, 3, 6, 7, 8};
 
    for (j=0; j<5; j++) {
        for (i=0; i<frames; i++) {
            int zac = ifs_indexes[j];
            int kon = ifs_indexes[(j+1) % 5];
            memset(histogram, 0, IFS_PIXELS * sizeof(float));
            SDL_LockSurface(pixmap);
            recalcIFS(max_iter, start_iter, (float)i/(frames-1.0), zac, kon);
            SDL_UnlockSurface(pixmap);
            gfx_bitblt(pixmap, (WINDOW_WIDTH-IMAGE_WIDTH)/2, (WINDOW_HEIGHT-IMAGE_HEIGHT)/2);
            SDL_Delay(10);
            gfx_flip();
 
            /* reagovat na zavreni okna aplikace i na klavesy Esc a Q */
            if (should_we_quit())
            {
                return;
            }
        }
        SDL_Delay(100);
    }
}
 
/*
 * Zaciname...
 */
int main(int argc, char **argv)
{
    /* inicializace */
    pixmap = SDL_CreateRGBSurface(SDL_SWSURFACE, IMAGE_WIDTH, IMAGE_HEIGHT, 24, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000);
    init_sdl();
 
    /* zobrazit animaci */
    animation(pixmap);
 
    /* ukonceni prace s SDL */
    finalize();
    return 0;
}
 
/* finito */

O překlad se postará nástroj „make“ s využitím následujícího souboru Makefile:

CC=gcc
CFLAGS=-Wall -pedantic -ansi -O9 -ffast-math
LFLAGS=-lSDLmain -lSDL
 
EXENAME=sdl_test
 
all:    $(EXENAME)
 
$(EXENAME):     sdl_test.o
        gcc -o $(EXENAME) $? $(LFLAGS)
 
sdl_test,o:     sdl_test.c
        $(CC) $(CFLAGS) -c -o $@ $<

6. Demonstrační příklad SDLTest70 – využití knihovny SDLJava při renderingu

Dnešní druhý demonstrační příklad počítá a zobrazuje stejnou animaci jako příklad předchozí, je ovšem naprogramovaný v Javě s využitím knihovny SDLJava. Jména metod i celková koncepce tohoto příkladu je odvozena od céčkové varianty aplikace, ovšem některé části (přístup k pixelům bitmapy) samozřejmě musely být modifikovány:

import sdljava.SDLMain;
import sdljava.SDLException;
import sdljava.SDLTimer;
 
import sdljava.event.SDLEvent;
import sdljava.event.SDLKeyboardEvent;
import sdljava.event.SDLKey;
import sdljava.event.SDLQuitEvent;
 
import sdljava.video.SDLSurface;
import sdljava.video.SDLRect;
import sdljava.video.SDLVideo;
 
import sdljava.x.swig.SDLPressedState;
 
 
 
/**
 * Sedmdesaty demonstracni priklad vyuzivajici knihovnu SDLjava.
 *
 * Vyuziti knihovny SDLJava pri renderingu.
 *
 * @author Pavel Tisnovsky
 */
public class SDLTest70 {
 
    /**
     * Horizontalni rozliseni vybraneho grafickeho rezimu ci okna.
     */
    private static final int WINDOW_WIDTH = 640;
 
    /**
     * Vertikalni rozliseni vybraneho grafickeho rezimu ci okna.
     */
    private static final int WINDOW_HEIGHT = 480;
 
    /**
     * Horizontalni rozliseni renderovaneho obrazku.
     */
    private static final int IMAGE_WIDTH = 320;
 
    /**
     * Vertikalni rozliseni renderovaneho obrazku.
     */
    private static final int IMAGE_HEIGHT = 240;
 
    /**
     * Bitova hloubka vybraneho grafickeho rezimu.
     * (0 znamena automaticky vyber, ovsem lze samozrejme pouzit
     * i hodnoty 8, 16, 24 ci 32, podle vlastnosti graficke karty)
     */
    private static final int GFX_BPP = 32;
 
    /**
     * Reference na data predstavujici framebuffer.
     */
    static SDLSurface screen = null;
 
    /**
     * Reference na bitmapu, do ktere se provadi rendering.
     */
    static SDLSurface pixmap = null;
 
    /**
     * Pouzito pri renderingu - celkovy pocet "zasahu" jednotlivych pixelu.
     */
    static int[][] histogram = new int[IMAGE_HEIGHT][IMAGE_WIDTH];
 
    /**
     * Transformacni matice (+koeficient pravdepodobnosti) jednotlivych IFS.
     */
    static float data[][] = new float[][] {
        { 0.500000f,  0.000000f,  0.000000f,  0.500000f, -2.563477f, -0.000003f,  0.333333f},
        { 0.500000f,  0.000000f,  0.000000f,  0.500000f,  2.436544f, -0.000003f,  0.333333f},
        { 0.000000f, -0.500000f,  0.500000f,  0.000000f,  4.873085f,  7.563492f,  0.333333f},
        { 1.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,  0.000000f,  1.000000f},
        { 1.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,  0.000000f,  1.000000f},
 
        { 0.307692f, -0.531469f, -0.461538f, -0.293706f,  5.401953f,  8.655175f,  0.400000f},
        { 0.307692f, -0.076923f,  0.153846f, -0.447552f, -1.295248f,  4.152990f,  0.150000f},
        { 0.000000f,  0.545455f,  0.692308f, -0.195804f, -4.893637f,  7.269794f,  0.450000f},
        { 1.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,  0.000000f,  1.000000f},
        { 1.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,  0.000000f,  1.000000f},
 
        { 0.696970f, -0.481061f, -0.393939f, -0.662879f,  2.147003f, 10.310288f,  0.747826f},
        { 0.090909f, -0.443182f,  0.515152f, -0.094697f,  4.286558f,  2.925762f,  0.252174f},
        { 1.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,  0.000000f,  1.000000f},
        { 1.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,  0.000000f,  1.000000f},
        { 1.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,  0.000000f,  1.000000f},
 
        { 0.824074f,  0.281482f, -0.212346f,  0.864198f, -1.882290f, -0.110607f,  0.787473f},
        { 0.088272f,  0.520988f, -0.463889f, -0.377778f,  0.785360f,  8.095795f,  0.212527f},
        { 1.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,  0.000000f,  1.000000f},
        { 1.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,  0.000000f,  1.000000f},
        { 1.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,  0.000000f,  1.000000f},
 
        { 0.824074f,  0.281481f, -0.212346f,  0.864197f, -1.772710f,  0.137795f,  0.771268f},
        {-0.138580f,  0.283951f, -0.670062f, -0.279012f,  2.930991f,  7.338924f,  0.228732f},
        { 1.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,  0.000000f,  1.000000f},
        { 1.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,  0.000000f,  1.000000f},
        { 1.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,  0.000000f,  1.000000f},
 
        { 0.870370f,  0.074074f, -0.115741f,  0.851852f, -1.278016f,  0.070331f,  0.798030f},
        {-0.162037f, -0.407407f,  0.495370f,  0.074074f,  6.835726f,  5.799174f,  0.201970f},
        { 1.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,  0.000000f,  1.000000f},
        { 1.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,  0.000000f,  1.000000f},
        { 1.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,  0.000000f,  1.000000f},
 
        { 0.850000f,  0.040000f, -0.040000f,  0.850000f,  0.000000f,  1.600000f,  0.850000f},
        { 0.200000f, -0.260000f,  0.230000f,  0.220000f,  0.000000f,  1.600000f,  0.070000f},
        {-0.150000f,  0.280000f,  0.260000f,  0.240000f,  0.000000f,  0.440000f,  0.070000f},
        { 0.000000f,  0.000000f,  0.000000f,  0.160000f,  0.000000f,  0.000000f,  0.010000f},
        { 1.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,  0.000000f,  1.000000f},
 
        { 0.307692f,  0.000000f,  0.000000f,  0.294118f,  4.119164f,  1.604278f,  0.151515f},
        { 0.192308f, -0.205882f,  0.653846f,  0.088235f, -0.688840f,  5.978916f,  0.253788f},
        { 0.192308f,  0.205882f, -0.653846f,  0.088235f,  0.668580f,  5.962514f,  0.253788f},
        { 0.307692f,  0.000000f,  0.000000f,  0.294118f, -4.136530f,  1.604278f,  0.151515f},
        { 0.384615f,  0.000000f,  0.000000f, -0.294118f, -0.007718f,  2.941176f,  1.000000f},
 
        { 0.787879f, -0.424242f,  0.242424f,  0.859848f,  1.758647f,  1.408065f,  0.895652f},
        {-0.121212f,  0.257576f,  0.151515f,  0.053030f, -6.721654f,  1.377236f,  0.052174f},
        { 0.181818f, -0.136364f,  0.090909f,  0.181818f,  6.086107f,  1.568035f,  0.052174f},
        { 1.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,  0.000000f,  1.000000f},
        { 1.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,  0.000000f,  1.000000f},
 
        { 0.000000f,  0.000000f,  0.000000f,  0.500000f,  0.000000f,  0.000000f,  0.050000f},
        { 0.420000f, -0.420000f,  0.420000f,  0.420000f,  0.000000f,  0.200000f,  0.400000f},
        { 0.420000f,  0.420000f, -0.420000f,  0.420000f,  0.000000f,  0.200000f,  0.400000f},
        { 0.100000f,  0.000000f,  0.000000f,  0.100000f,  0.000000f,  0.200000f,  0.150000f},
        { 1.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,  0.000000f,  1.000000f},
 
        { 0.500000f,  0.000000f,  0.000000f,  0.500000f, -0.500000f,  0.000000f,  0.333333f},
        { 0.500000f,  0.000000f,  0.000000f,  0.500000f,  0.500000f,  0.000000f,  0.333333f},
        { 0.500000f,  0.000000f,  0.000000f,  0.500000f,  0.000000f,  0.860000f,  0.333334f},
        { 1.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,  0.000000f,  1.000000f},
        { 1.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,  0.000000f,  1.000000f},
    };
 
    /**
     * Inicializace grafickeho rezimu ci otevreni okna pro vykreslovani.
     */
    private static void init_sdl()
            throws SDLException {
        final long flags = SDLVideo.SDL_DOUBLEBUF;
        screen = SDLVideo.setVideoMode(WINDOW_WIDTH, WINDOW_HEIGHT, GFX_BPP, flags);
    }
 
    /**
     * Ukonceni prace aplikace (predevsim uvolneni framebufferu i bitmapy pro renderovani fraktalu).
     */
    private static void finalize_app()
            throws SDLException {
        pixmap.freeSurface();
        screen.freeSurface();
    }
 
    /**
     * Provedeni operace typu BitBlt (Bit Block Transfer)
     */
    private static void gfx_bitblt(SDLSurface surface, final int x, final int y)
            throws SDLException {
        SDLRect dst_rect = new SDLRect(x, y);
        surface.blitSurface(screen, dst_rect);
    }
 
    /**
     * Prohozeni predniho a zadniho bufferu.
     */
    private static void gfx_flip()
            throws SDLException {
        screen.flip();
    }
 
    /**
     * Prepocet obrazku s IFS fraktalem.
     */
    private static void recalcIFS(int max_iter, int start_iter, float morph_ratio, int first_ifs, int second_ifs)
            throws SDLException
    {
        final float scale_factor=12.0f;
        final float scale_factor_x = pixmap.getWidth() / scale_factor;
        final float scale_factor_y = pixmap.getHeight() / scale_factor;
        final float xmin=-6.0f;
        final float ymin=-1.0f;
 
        float x1=0, y1=0, x2, y2;
        int   i, j, k;
        float maxp=0;
 
        /* primy pristup k pixelum */
        java.nio.ByteBuffer pixels = pixmap.getPixelData();
 
        float[][] a = new float[5][7];
 
        /* vypocet vsech peti transformacnich matic na zaklade hodnoty morph_ratio */
        for (j=0; j<5; j++)
        {
            /* projit prvky transformacni matice i koeficientem pravdepodobnosti,
             * ktery je ulozen za posledni prvek transformacni matice */
            for (i=0; i<7; i++)
            {
                a[j][i]=(1.0f-morph_ratio)*data[j+first_ifs*5][i]
                             +(morph_ratio)*data[j+second_ifs*5][i];
            }
        }
 
        /* vlastni vypocet IFS fraktalu */
        for (i=0; i<max_iter; i++)
        {
            float pp = (float)Math.random();
            float sum=0;
            for (k=0; sum<=pp; k++)
                sum+=a[k][6];
            k--;
            x2 = x1*a[k][0] + y1*a[k][1] + a[k][4];
            y2 = x1*a[k][2] + y1*a[k][3] + a[k][5];
            x1 = x2;
            y1 = y2;
            if (i > start_iter)
            {
                int x = (int) ((x1 - xmin) * scale_factor_x);
                int y = (int) ((y1 - ymin) * scale_factor_y);
                if (x >= 0 && y >=0 && x < pixmap.getWidth() && y < pixmap.getHeight())
                {
                    histogram[y][x]++;
                }
            }
        }
 
        /* vypocet maxp pro normalizaci obrazu */
        for (int[] row : histogram)
        {
            for (int ip : row)
            {
                if (maxp<ip) maxp=ip;
            }
        }
        /* prepocet konstanty pro normalizaci */
        maxp = (float)(255.0 / Math.log(maxp));
 
        /* vlastni rendering */
        int index = 0;
        for (int[] row : histogram)
        {
            for (int ip : row)
            {
                int color = 0xff & (int)(Math.log(ip)*maxp);
                color = ~color;
                // barvy pixelu se mohou vyplnit pres metody nabizene tridou ByteBuffer
                pixels.put(index++, (byte)color);
                pixels.put(index++, (byte)color);
                pixels.put(index++, (byte)color);
            }
        }
    }
 
    /**
     * Reagovat na zavreni okna aplikace i na klavesy Esc a Q.
     */
    static private boolean should_we_quit()
            throws SDLException {
        // precist udalost z fronty
        SDLEvent event = SDLEvent.pollEvent();;
 
        // vyskok ze smycky pro zpracovani udalosti pri vyskytu
        // udalosti typu SDLQuitEvent
        if (event instanceof SDLQuitEvent) {
            return true;
        }
 
        // stisk ci pusteni klavesy
        if (event instanceof SDLKeyboardEvent) {
            // pretypovani
            final SDLKeyboardEvent keyEvent = (SDLKeyboardEvent)event;
 
            // symbol/kod klavesy
            final int symbol = keyEvent.getSym();
 
            if (keyEvent.getState() == SDLPressedState.PRESSED) {
                switch (symbol) {
                    case SDLKey.SDLK_ESCAPE: // klavesa ESC ukonci program
                    case SDLKey.SDLK_q:      // klavesa Q taktez ukonci program
                        return true;
                    default:
                        break;
                }
            }
        }
        return false;
    }
 
    /**
     * Vlastni animace.
     */
    public static void animation() throws InterruptedException, SDLException
    {
        int max_iter = 50000;
        int start_iter = 100;
        int frames = 100;
        int i, j;
 
        /* prvky tohoto pole predstavuje prechody mezi jednotlivymi IFS. */
        int ifs_indexes[] = {0, 3, 6, 7, 8};
 
        for (j = 0; j < 5; j++) {
            for (i = 0; i < frames; i++) {
                int zac = ifs_indexes[j];
                int kon = ifs_indexes[(j+1) % 5];
                for (int[] row: histogram) {
                    java.util.Arrays.fill(row, 0);
                }
                pixmap.lockSurface();
                recalcIFS(max_iter, start_iter, (float)i/(frames-1.0f), zac, kon);
                pixmap.unlockSurface();
                gfx_bitblt(pixmap, (WINDOW_WIDTH-IMAGE_WIDTH)/2, (WINDOW_HEIGHT-IMAGE_HEIGHT)/2);
                SDLTimer.delay(10);
                gfx_flip();
 
                /* reagovat na zavreni okna aplikace i na klavesy Esc a Q */
                if (should_we_quit())
                {
                    return;
                }
            }
            SDLTimer.delay(100);
        }
    }
 
    /**
     * Spusteni sedmdesateho demonstracniho prikladu.
     */
    public static void main(String[] args) {
        try {
            // inicializace knihovny SDLJava
            SDLMain.init(SDLMain.SDL_INIT_VIDEO);
 
            // inicializace bitmapy pro rendering
            pixmap = SDLVideo.createRGBSurface(SDLVideo.SDL_SWSURFACE, IMAGE_WIDTH, IMAGE_HEIGHT, 24, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000);
 
            // inicializace celoobrazovkoveho grafickeho rezimu ci otevreni okna pro vykreslovani
            init_sdl();
 
            // zobrazit animaci
            animation();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            try {
                finalize_app();
            }
            catch (SDLException e) {
                e.printStackTrace();
            }
            // musime obnovit puvodni graficky rezim
            // i v tom pripade, ze nastane nejaka vyjimka
            SDLMain.quit();
        }
    }
 
}

Skript pro překlad tohoto demonstračního příkladu na Linuxu:

#!/bin/sh
 
SDL_JAVA_LIBS=./sdljava-0.9.1/lib
 
javac -cp $SDL_JAVA_LIBS/sdljava.jar SDLTest70.java

Dávkový soubor pro překlad tohoto demonstračního příkladu na Windows:

set SDL_JAVA_LIBS=.\sdljava-0.9.1\lib
 
javac -cp %SDL_JAVA_LIBS%\sdljava.jar SDLTest70.java

Skript pro spuštění na Linuxu:

#!/bin/sh
 
SDL_JAVA_LIBS=./sdljava-0.9.1/lib
 
java -cp .:$SDL_JAVA_LIBS/sdljava.jar -Djava.library.path=$SDL_JAVA_LIBS SDLTest70

Dávkový soubor pro spuštění na Windows:

set SDL_JAVA_LIBS=.\sdljava-0.9.1\lib
 
java -cp .;%SDL_JAVA_LIBS%\sdljava.jar -Djava.library.path=%SDL_JAVA_LIBS% SDLTest70

7. Porovnání času běhu obou demonstračních příkladů

Zajímavé bude určitě porovnání času běhu obou demonstračních příkladů. V první tabulce jsou ukázány výstupy z utility „time“ na obstarožním počítači s mikroprocesorem AMD Duron:

? Nativní C+SDL JVM režim client JVM režim server
real 0m24.571s 0m40.098s 0m57.457s
user 0m13.777s 0m27.990s 0m44.903s
sys 0m0.292s 0m0.532s 0m0.708s

JVM (konkrétně 1.6.0) v tomto případě v porovnání s nativní aplikací nedopadlo nijak dobře, ale zkusme se podívat, jak testování dopadne na stroji vybaveném přeci jen novějším procesorem Intel Core2 Duo:

? Nativní C+SDL JVM režim client JVM režim server
real 0m18.201s 0m20.906s 0m20.836s
user 0m12.052s 0m14.804s 0m14.796s
sys 0m0.026s 0m0.112s 0m0.089s

Zde již jsou časy srovnatelné a navíc se v nich již ve větší míře projeví naprogramované pauzy mezi jednotlivými snímky.

Pro úplnost se podívejme na výstup profileru, z něhož je patrné, kterou část kódu by bylo ideální optimalizovat:

widgety

3225600 java.nio.Buffer.checkIndex(I)I java.nio.DirectByteBuffer.put(IB)Ljava/nio/ByteBuffer; 9062
3225600 java.nio.DirectByteBuffer.ix(I)J java.nio.DirectByteBuffer.put(IB)Ljava/nio/ByteBuffer; 9580
3225600 java.nio.DirectByteBuffer.put(IB)Ljava/nio/ByteBuffer; SDLTest70.recalcIFS(IIFII)V 54959
1400000 java.util.concurrent.atomic.AtomicLong.get()J java.util.Random.next(I)I 3757
1400000 java.util.concurrent.atomic.AtomicLong.compareAndSet(JJ)Z java.util.Random.next(I)I 4272
1400000 java.util.Random.next(I)I java.util.Random.nextDouble()D 24052
700000 java.util.Random.nextDouble()D java.lang.Math.random()D 31061
700000 java.lang.Math.random()D SDLTest70.recalcIFS(IIFII)V 36660
698614 sdljava.x.swig.SDL_Surface.getW()I sdljava.video.SDLSurface.getWidth()I 2010
698614 sdljava.x.swig.SDL_Surface.getH()I sdljava.video.SDLSurface.getHeight()I 1594
698600 sdljava.video.SDLSurface.getWidth()I SDLTest70.recalcIFS(IIFII)V 7195
698600 sdljava.video.SDLSurface.getHeight()I SDLTest70.recalcIFS(IIFII)V 6816

Zajímavé a možná i typické je, že se jedná přesně o tu část kódu, která je v C variantě naprogramována s využitím ukazatelů a (nekontrolovaného) přímého přístupu do paměti :-)

8. Repositář se zdrojovými kódy obou dnešních demonstračních příkladů

Oba dva dnes popsané demonstrační příklady byly společně s podpůrnými skripty určenými pro jejich překlad a následné spuštění uloženy do Mercurial repositáře dostupného na adrese http://icedtea.classpath.or­g/people/ptisnovs/jvm-tools/. Podobně jako tomu bylo i v předchozích několika dílech tohoto seriálu, i ke dnešní dvojici příkladů jsou přiloženy skripty využitelné pro jejich překlad a spuštění:

9. Odkazy na Internetu

  1. Audio File Formats.
    http://sox.sourceforge.net/Au­dioFormats-11.html
  2. TestSounds.com: pure digital sounds to test your audio
    http://www.testsounds.com/
  3. Test Tones (20hz – 20khz)
    http://mdf1.tripod.com/test-tones.html
  4. WAV (Wikipedia)
    http://en.wikipedia.org/wiki/WAV
  5. WAVE PCM soundfile format
    https://ccrma.stanford.edu/cou­rses/422/projects/WaveFor­mat/
  6. Audio Interchange File Format
    http://en.wikipedia.org/wiki/Aiff
  7. Musical Instrument Digital Interface,
    http://en.wikipedia.org/wi­ki/Musical_Instrument_Digi­tal_Interface
  8. A MIDI Pedalboard Encode,
    http://www.pykett.org.uk/a_mi­di_pedalboard_encoder.htm
  9. MIDI Note Number, Frequency Table,
    http://tonalsoft.com/pub/news/pitch-bend.aspx
  10. Note names, MIDI numbers and frequencies,
    http://www.phys.unsw.edu.au­/jw/notes.html
  11. The MIDI Specification,
    http://www.gweep.net/~pre­fect/eng/reference/protocol/mi­dispec.html
  12. Essentials of the MIDI protocol,
    http://ccrma.stanford.edu/~cra­ig/articles/linuxmidi/mis­c/essenmidi.html
  13. General MIDI,
    http://en.wikipedia.org/wi­ki/General_MIDI
  14. Obecné MIDI (General MIDI),
    http://www-kiv.zcu.cz/~herout/html_sbo/mi­di/5.html
  15. Custom Chips: Paula
    http://www.amiga-hardware.com/showhardware­.cgi?HARDID=1460
  16. Big Book of Amiga Hardware
    http://www.amiga-resistance.info/bboahfaq/
  17. Amiga Hardware Database
    http://amiga.resource.cx/
  18. ExoticA
    http://www.exotica.org.uk/wi­ki/Main_Page
  19. The absolute basics of Amiga audio
    http://www.sufo.estates.co­.uk/amiga/amimus.html
  20. Wikipedia: Tracker
    http://en.wikipedia.org/wiki/Tracker
  21. Wikipedia: Trackers
    http://en.wikipedia.org/wiki/Trackers
  22. Ultimate Soundtracker
    http://en.wikipedia.org/wi­ki/Ultimate_Soundtracker
  23. Protracker
    http://en.wikipedia.org/wi­ki/ProTracker
  24. Impulse Tracker
    http://en.wikipedia.org/wi­ki/Impulse_Tracker
  25. Scream Tracker
    http://en.wikipedia.org/wi­ki/ScreamTracker
  26. MikMod for Java
    http://jmikmod.berlios.de/
  27. List of audio trackers
    http://en.wikipedia.org/wi­ki/List_of_audio_trackers
  28. Wikipedia: Module File
    http://en.wikipedia.org/wi­ki/Module_file
  29. Wikipedia: Chiptune
    http://en.wikipedia.org/wiki/Chiptune
  30. SDL_mixer 2.0
    http://www.libsdl.org/pro­jects/SDL_mixer/
  31. SDLJava: package sdljava.ttf
    http://sdljava.sourceforge­.net/docs/api/sdljava/ttf/pac­kage-summary.html#package_description
  32. SDLJava: class sdljava.ttf.SDLTTF
    http://sdljava.sourceforge­.net/docs/api/sdljava/ttf/SDLTTF­.html
  33. SDLJava: class sdljava.ttf.SDLTrueTypeFont
    http://sdljava.sourceforge­.net/docs/api/sdljava/ttf/SDLTru­eTypeFont.html
  34. SDL_ttf Documentation
    http://www.libsdl.org/pro­jects/SDL_ttf/docs/
  35. SDL_ttf 2.0 (není prozatím součástí SDLJava)
    http://www.libsdl.org/pro­jects/SDL_ttf/
  36. SDL_ttf doc
    http://www.libsdl.org/pro­jects/SDL_ttf/docs/SDL_ttf_fra­me.html
  37. SDL 1.2 Documentation: SDL_Surface
    http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlsurface.html
  38. SDL 1.2 Documentation: SDL_PixelFormat
    http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlpixelformat.html
  39. SDL 1.2 Documentation: SDL_LockSurface
    http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdllocksurface.html
  40. SDL 1.2 Documentation: SDL_UnlockSurface
    http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlunlocksurface.html
  41. SDL 1.2 Documentation: SDL_LoadBMP
    http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlloadbmp.html
  42. SDL 1.2 Documentation: SDL_SaveBMP
    http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlsavebmp.html
  43. SDL 1.2 Documentation: SDL_BlitSurface
    http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlblitsurface.html
  44. SDL 1.2 Documentation: SDL_VideoInfo
    http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlvideoinfo.html
  45. SDL 1.2 Documentation: SDL_GetVideoInfo
    http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlgetvideoinfo.html
  46. glDrawArrays
    http://www.opengl.org/sdk/doc­s/man4/xhtml/glDrawArrays­.xml
  47. glDrawElements
    http://www.opengl.org/sdk/doc­s/man4/xhtml/glDrawElemen­ts.xml
  48. glDrawArraysInstanced
    http://www.opengl.org/sdk/doc­s/man4/xhtml/glDrawArraysIn­stanced.xml
  49. glDrawElementsInstanced
    http://www.opengl.org/sdk/doc­s/man4/xhtml/glDrawElemen­tsInstanced.xml
  50. Root.cz: Seriál Grafická knihovna OpenGL
    http://www.root.cz/serialy/graficka-knihovna-opengl/
  51. Root.cz: Seriál Tvorba přenositelných grafických aplikací využívajících knihovnu GLUT
    http://www.root.cz/serialy/tvorba-prenositelnych-grafickych-aplikaci-vyuzivajicich-knihovnu-glut/
  52. Best Practices for Working with Vertex Data
    https://developer.apple.com/li­brary/ios/documentation/3ddra­wing/conceptual/opengles_pro­grammingguide/Techniquesfor­WorkingwithVertexData/Techni­quesforWorkingwithVertexDa­ta.html
  53. Class BufferStrategy
    http://docs.oracle.com/ja­vase/6/docs/api/java/awt/i­mage/BufferStrategy.html
  54. Class Graphics
    http://docs.oracle.com/ja­vase/1.5.0/docs/api/java/aw­t/Graphics.html
  55. Double Buffering and Page Flipping
    http://docs.oracle.com/ja­vase/tutorial/extra/fullscre­en/doublebuf.html
  56. BufferStrategy and BufferCapabilities
    http://docs.oracle.com/ja­vase/tutorial/extra/fullscre­en/bufferstrategy.html
  57. Java:Tutorials:Double Buffering
    http://content.gpwiki.org/in­dex.php/Java:Tutorials:Dou­ble_Buffering
  58. Double buffer in standard Java AWT
    http://www.codeproject.com/Ar­ticles/2136/Double-buffer-in-standard-Java-AWT
  59. Java 2D: Hardware Accelerating – Part 1 – Volatile Images
    http://www.javalobby.org/fo­rums/thread.jspa?threadID=16840&tstar­t=0
  60. Java 2D: Hardware Accelerating – Part 2 – Buffer Strategies
    http://www.javalobby.org/ja­va/forums/t16867.html
  61. How does paintComponent work?
    http://stackoverflow.com/qu­estions/15544549/how-does-paintcomponent-work
  62. A Swing Architecture Overview
    http://www.oracle.com/technet­work/java/architecture-142923.html
  63. Class javax.swing.JComponent
    http://docs.oracle.com/ja­vase/6/docs/api/javax/swin­g/JComponent.html
  64. Class java.awt.Component
    http://docs.oracle.com/ja­vase/6/docs/api/java/awt/Com­ponent.html
  65. Class java.awt.Component.BltBufferStrategy
    http://docs.oracle.com/ja­vase/6/docs/api/java/awt/Com­ponent.BltBufferStrategy.html
  66. Class java.awt.Component.FlipBufferStrategy
    http://docs.oracle.com/ja­vase/6/docs/api/java/awt/Com­ponent.FlipBufferStrategy­.html
  67. Metoda java.awt.Component.isDoubleBuffered()
    http://docs.oracle.com/ja­vase/6/docs/api/java/awt/Com­ponent.html#isDoubleBuffe­red()
  68. Metoda javax.swing.JComponent.is­DoubleBuffered()
    http://docs.oracle.com/ja­vase/6/docs/api/javax/swin­g/JComponent.html#isDouble­Buffered()
  69. Metoda javax.swing.JComponent.set­DoubleBuffered()
    http://docs.oracle.com/ja­vase/6/docs/api/javax/swin­g/JComponent.html#setDouble­Buffered(boolean)
  70. Javadoc – třída GraphicsDevice
    http://docs.oracle.com/ja­vase/7/docs/api/java/awt/Grap­hicsDevice.html
  71. Javadoc – třída GraphicsEnvironment
    http://docs.oracle.com/ja­vase/7/docs/api/java/awt/Grap­hicsEnvironment.html
  72. Javadoc – třída GraphicsConfiguration
    http://docs.oracle.com/ja­vase/7/docs/api/java/awt/Grap­hicsConfiguration.html
  73. Javadoc – třída DisplayMode
    http://docs.oracle.com/ja­vase/7/docs/api/java/awt/Dis­playMode.html
  74. Lesson: Full-Screen Exclusive Mode API
    http://docs.oracle.com/ja­vase/tutorial/extra/fullscre­en/
  75. Full-Screen Exclusive Mode
    http://docs.oracle.com/ja­vase/tutorial/extra/fullscre­en/exclusivemode.html
  76. Display Mode
    http://docs.oracle.com/ja­vase/tutorial/extra/fullscre­en/displaymode.html
  77. Using the Full-Screen Exclusive Mode API in Java
    http://www.developer.com/ja­va/other/article.php/3609776/U­sing-the-Full-Screen-Exclusive-Mode-API-in-Java.htm
  78. Java quick guide: JVM Instruction Set (tabulka všech instrukcí JVM)
    http://www.mobilefish.com/tu­torials/java/java_quickgu­ide_jvm_instruction_set.html
  79. The JVM Instruction Set
    http://mpdeboer.home.xs4a­ll.nl/scriptie/node14.html
  80. MultiMedia eXtensions
    http://softpixel.com/~cwrig­ht/programming/simd/mmx.phpi
  81. SSE (Streaming SIMD Extentions)
    http://www.songho.ca/misc/sse/sse­.html
  82. Timothy A. Chagnon: SSE and SSE2
    http://www.cs.drexel.edu/~tc365/mpi-wht/sse.pdf
  83. Intel corporation: Extending the Worldr's Most Popular Processor Architecture
    http://download.intel.com/techno­logy/architecture/new-instructions-paper.pdf
  84. SIMD architectures:
    http://arstechnica.com/ol­d/content/2000/03/simd.ar­s/
  85. GC safe-point (or safepoint) and safe-region
    http://xiao-feng.blogspot.cz/2008/01/gc-safe-point-and-safe-region.html
  86. Safepoints in HotSpot JVM
    http://blog.ragozin.info/2012/10/sa­fepoints-in-hotspot-jvm.html
  87. Java theory and practice: Synchronization optimizations in Mustang
    http://www.ibm.com/develo­perworks/java/library/j-jtp10185/
  88. How to build hsdis
    http://hg.openjdk.java.net/jdk7/hot­spot/hotspot/file/tip/src/sha­re/tools/hsdis/README
  89. Java SE 6 Performance White Paper
    http://www.oracle.com/technet­work/java/6-performance-137236.html
  90. Lukas Stadler's Blog
    http://classparser.blogspot­.cz/2010/03/hsdis-i386dll.html
  91. How to build hsdis-amd64.dll and hsdis-i386.dll on Windows
    http://dropzone.nfshost.com/hsdis.htm
  92. PrintAssembly
    https://wikis.oracle.com/dis­play/HotSpotInternals/Prin­tAssembly
  93. The Java Virtual Machine Specification: 3.14. Synchronization
    http://docs.oracle.com/ja­vase/specs/jvms/se7/html/jvms-3.html#jvms-3.14
  94. The Java Virtual Machine Specification: 8.3.1.4. volatile Fields
    http://docs.oracle.com/ja­vase/specs/jls/se7/html/jls-8.html#jls-8.3.1.4
  95. The Java Virtual Machine Specification: 17.4. Memory Model
    http://docs.oracle.com/ja­vase/specs/jls/se7/html/jls-17.html#jls-17.4
  96. The Java Virtual Machine Specification: 17.7. Non-atomic Treatment of double and long
    http://docs.oracle.com/ja­vase/specs/jls/se7/html/jls-17.html#jls-17.7
  97. Open Source ByteCode Libraries in Java
    http://java-source.net/open-source/bytecode-libraries
  98. ASM Home page
    http://asm.ow2.org/
  99. Seznam nástrojů využívajících projekt ASM
    http://asm.ow2.org/users.html
  100. ObjectWeb ASM (Wikipedia)
    http://en.wikipedia.org/wi­ki/ObjectWeb_ASM
  101. Java Bytecode BCEL vs ASM
    http://james.onegoodcooki­e.com/2005/10/26/java-bytecode-bcel-vs-asm/
  102. BCEL Home page
    http://commons.apache.org/bcel/
  103. Byte Code Engineering Library (před verzí 5.0)
    http://bcel.sourceforge.net/
  104. Byte Code Engineering Library (verze >= 5.0)
    http://commons.apache.org/pro­per/commons-bcel/
  105. BCEL Manual
    http://commons.apache.org/bcel/ma­nual.html
  106. Byte Code Engineering Library (Wikipedia)
    http://en.wikipedia.org/wiki/BCEL
  107. BCEL Tutorial
    http://www.smfsupport.com/sup­port/java/bcel-tutorial!/
  108. Bytecode Engineering
    http://book.chinaunix.net/spe­cial/ebook/Core_Java2_Volu­me2AF/0131118269/ch13lev1sec6­.html
  109. Bytecode Outline plugin for Eclipse (screenshoty + info)
    http://asm.ow2.org/eclipse/index.html
  110. Javassist
    http://www.jboss.org/javassist/
  111. Byteman
    http://www.jboss.org/byteman
  112. Java programming dynamics, Part 7: Bytecode engineering with BCEL
    http://www.ibm.com/develo­perworks/java/library/j-dyn0414/
  113. The JavaTM Virtual Machine Specification, Second Edition
    http://java.sun.com/docs/bo­oks/jvms/second_edition/html/VMSpec­TOC.doc.html
  114. The class File Format
    http://java.sun.com/docs/bo­oks/jvms/second_edition/html/Clas­sFile.doc.html
  115. javap – The Java Class File Disassembler
    http://docs.oracle.com/ja­vase/1.4.2/docs/tooldocs/win­dows/javap.html
  116. javap-java-1.6.0-openjdk(1) – Linux man page
    http://linux.die.net/man/1/javap-java-1.6.0-openjdk
  117. Using javap
    http://www.idevelopment.in­fo/data/Programming/java/mis­cellaneous_java/Using_javap­.html
  118. Examine class files with the javap command
    http://www.techrepublic.com/ar­ticle/examine-class-files-with-the-javap-command/5815354
  119. aspectj (Eclipse)
    http://www.eclipse.org/aspectj/
  120. Aspect-oriented programming (Wikipedia)
    http://en.wikipedia.org/wi­ki/Aspect_oriented_program­ming
  121. AspectJ (Wikipedia)
    http://en.wikipedia.org/wiki/AspectJ
  122. EMMA: a free Java code coverage tool
    http://emma.sourceforge.net/
  123. Cobertura
    http://cobertura.sourceforge.net/
  124. jclasslib bytecode viewer
    http://www.ej-technologies.com/products/jclas­slib/overview.html
Našli jste v článku chybu?
Podnikatel.cz: Byla finanční manažerka, teď cvičí jógu

Byla finanční manažerka, teď cvičí jógu

DigiZone.cz: Ultra HD v praxi a v Portugalsku

Ultra HD v praxi a v Portugalsku

DigiZone.cz: Parlamentní listy: kde končí PR...

Parlamentní listy: kde končí PR...

Vitalia.cz: Test dětských svačinek: Tyhle ne!

Test dětských svačinek: Tyhle ne!

Vitalia.cz: Tahák, jak vyzrát nad zápachem z úst

Tahák, jak vyzrát nad zápachem z úst

Lupa.cz: Jak levné procesory změnily svět?

Jak levné procesory změnily svět?

DigiZone.cz: DVB-T2 ověřeno: seznam TV zveřejněn

DVB-T2 ověřeno: seznam TV zveřejněn

Vitalia.cz: Tradiční čínská medicína a rakovina

Tradiční čínská medicína a rakovina

DigiZone.cz: Technisat připravuje trojici DAB

Technisat připravuje trojici DAB

DigiZone.cz: Numan Two: rozhlasový přijímač s CD

Numan Two: rozhlasový přijímač s CD

DigiZone.cz: Nova opět stahuje „milionáře“

Nova opět stahuje „milionáře“

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

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

120na80.cz: Nejsilnější alergeny jsou pryč

Nejsilnější alergeny jsou pryč

Vitalia.cz: Muž, který miluje příliš. Ženám neimponuje

Muž, který miluje příliš. Ženám neimponuje

Lupa.cz: Proč jsou firemní počítače pomalé?

Proč jsou firemní počítače pomalé?

Vitalia.cz: dTest odhalil ten nejlepší kečup

dTest odhalil ten nejlepší kečup

Lupa.cz: Jak se prodává firma za miliardu?

Jak se prodává firma za miliardu?

Podnikatel.cz: Tyto pojmy k #EET byste měli znát

Tyto pojmy k #EET byste měli znát

Vitalia.cz: 5 chyb, které děláme při skladování potravin

5 chyb, které děláme při skladování potravin

Vitalia.cz: Tohle jsou nejlepší česká piva podle odborníků

Tohle jsou nejlepší česká piva podle odborníků