Obsah
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ů
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:
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.org/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
- Audio File Formats.
http://sox.sourceforge.net/AudioFormats-11.html - TestSounds.com: pure digital sounds to test your audio
http://www.testsounds.com/ - Test Tones (20hz – 20khz)
http://mdf1.tripod.com/test-tones.html - WAV (Wikipedia)
http://en.wikipedia.org/wiki/WAV - WAVE PCM soundfile format
https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ - Audio Interchange File Format
http://en.wikipedia.org/wiki/Aiff - Musical Instrument Digital Interface,
http://en.wikipedia.org/wiki/Musical_Instrument_Digital_Interface - A MIDI Pedalboard Encode,
http://www.pykett.org.uk/a_midi_pedalboard_encoder.htm - MIDI Note Number, Frequency Table,
http://tonalsoft.com/pub/news/pitch-bend.aspx - Note names, MIDI numbers and frequencies,
http://www.phys.unsw.edu.au/jw/notes.html - The MIDI Specification,
http://www.gweep.net/~prefect/eng/reference/protocol/midispec.html - Essentials of the MIDI protocol,
http://ccrma.stanford.edu/~craig/articles/linuxmidi/misc/essenmidi.html - General MIDI,
http://en.wikipedia.org/wiki/General_MIDI - Obecné MIDI (General MIDI),
http://www-kiv.zcu.cz/~herout/html_sbo/midi/5.html - Custom Chips: Paula
http://www.amiga-hardware.com/showhardware.cgi?HARDID=1460 - Big Book of Amiga Hardware
http://www.amiga-resistance.info/bboahfaq/ - Amiga Hardware Database
http://amiga.resource.cx/ - ExoticA
http://www.exotica.org.uk/wiki/Main_Page - The absolute basics of Amiga audio
http://www.sufo.estates.co.uk/amiga/amimus.html - Wikipedia: Tracker
http://en.wikipedia.org/wiki/Tracker - Wikipedia: Trackers
http://en.wikipedia.org/wiki/Trackers - Ultimate Soundtracker
http://en.wikipedia.org/wiki/Ultimate_Soundtracker - Protracker
http://en.wikipedia.org/wiki/ProTracker - Impulse Tracker
http://en.wikipedia.org/wiki/Impulse_Tracker - Scream Tracker
http://en.wikipedia.org/wiki/ScreamTracker - MikMod for Java
http://jmikmod.berlios.de/ - List of audio trackers
http://en.wikipedia.org/wiki/List_of_audio_trackers - Wikipedia: Module File
http://en.wikipedia.org/wiki/Module_file - Wikipedia: Chiptune
http://en.wikipedia.org/wiki/Chiptune - SDL_mixer 2.0
http://www.libsdl.org/projects/SDL_mixer/ - SDLJava: package sdljava.ttf
http://sdljava.sourceforge.net/docs/api/sdljava/ttf/package-summary.html#package_description - SDLJava: class sdljava.ttf.SDLTTF
http://sdljava.sourceforge.net/docs/api/sdljava/ttf/SDLTTF.html - SDLJava: class sdljava.ttf.SDLTrueTypeFont
http://sdljava.sourceforge.net/docs/api/sdljava/ttf/SDLTrueTypeFont.html - SDL_ttf Documentation
http://www.libsdl.org/projects/SDL_ttf/docs/ - SDL_ttf 2.0 (není prozatím součástí SDLJava)
http://www.libsdl.org/projects/SDL_ttf/ - SDL_ttf doc
http://www.libsdl.org/projects/SDL_ttf/docs/SDL_ttf_frame.html - SDL 1.2 Documentation: SDL_Surface
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlsurface.html - SDL 1.2 Documentation: SDL_PixelFormat
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlpixelformat.html - SDL 1.2 Documentation: SDL_LockSurface
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdllocksurface.html - SDL 1.2 Documentation: SDL_UnlockSurface
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlunlocksurface.html - SDL 1.2 Documentation: SDL_LoadBMP
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlloadbmp.html - SDL 1.2 Documentation: SDL_SaveBMP
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlsavebmp.html - SDL 1.2 Documentation: SDL_BlitSurface
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlblitsurface.html - SDL 1.2 Documentation: SDL_VideoInfo
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlvideoinfo.html - SDL 1.2 Documentation: SDL_GetVideoInfo
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlgetvideoinfo.html - glDrawArrays
http://www.opengl.org/sdk/docs/man4/xhtml/glDrawArrays.xml - glDrawElements
http://www.opengl.org/sdk/docs/man4/xhtml/glDrawElements.xml - glDrawArraysInstanced
http://www.opengl.org/sdk/docs/man4/xhtml/glDrawArraysInstanced.xml - glDrawElementsInstanced
http://www.opengl.org/sdk/docs/man4/xhtml/glDrawElementsInstanced.xml - Root.cz: Seriál Grafická knihovna OpenGL
http://www.root.cz/serialy/graficka-knihovna-opengl/ - 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/ - Best Practices for Working with Vertex Data
https://developer.apple.com/library/ios/documentation/3ddrawing/conceptual/opengles_programmingguide/TechniquesforWorkingwithVertexData/TechniquesforWorkingwithVertexData.html - Class BufferStrategy
http://docs.oracle.com/javase/6/docs/api/java/awt/image/BufferStrategy.html - Class Graphics
http://docs.oracle.com/javase/1.5.0/docs/api/java/awt/Graphics.html - Double Buffering and Page Flipping
http://docs.oracle.com/javase/tutorial/extra/fullscreen/doublebuf.html - BufferStrategy and BufferCapabilities
http://docs.oracle.com/javase/tutorial/extra/fullscreen/bufferstrategy.html - Java:Tutorials:Double Buffering
http://content.gpwiki.org/index.php/Java:Tutorials:Double_Buffering - Double buffer in standard Java AWT
http://www.codeproject.com/Articles/2136/Double-buffer-in-standard-Java-AWT - Java 2D: Hardware Accelerating – Part 1 – Volatile Images
http://www.javalobby.org/forums/thread.jspa?threadID=16840&tstart=0 - Java 2D: Hardware Accelerating – Part 2 – Buffer Strategies
http://www.javalobby.org/java/forums/t16867.html - How does paintComponent work?
http://stackoverflow.com/questions/15544549/how-does-paintcomponent-work - A Swing Architecture Overview
http://www.oracle.com/technetwork/java/architecture-142923.html - Class javax.swing.JComponent
http://docs.oracle.com/javase/6/docs/api/javax/swing/JComponent.html - Class java.awt.Component
http://docs.oracle.com/javase/6/docs/api/java/awt/Component.html - Class java.awt.Component.BltBufferStrategy
http://docs.oracle.com/javase/6/docs/api/java/awt/Component.BltBufferStrategy.html - Class java.awt.Component.FlipBufferStrategy
http://docs.oracle.com/javase/6/docs/api/java/awt/Component.FlipBufferStrategy.html - Metoda java.awt.Component.isDoubleBuffered()
http://docs.oracle.com/javase/6/docs/api/java/awt/Component.html#isDoubleBuffered() - Metoda javax.swing.JComponent.isDoubleBuffered()
http://docs.oracle.com/javase/6/docs/api/javax/swing/JComponent.html#isDoubleBuffered() - Metoda javax.swing.JComponent.setDoubleBuffered()
http://docs.oracle.com/javase/6/docs/api/javax/swing/JComponent.html#setDoubleBuffered(boolean) - Javadoc – třída GraphicsDevice
http://docs.oracle.com/javase/7/docs/api/java/awt/GraphicsDevice.html - Javadoc – třída GraphicsEnvironment
http://docs.oracle.com/javase/7/docs/api/java/awt/GraphicsEnvironment.html - Javadoc – třída GraphicsConfiguration
http://docs.oracle.com/javase/7/docs/api/java/awt/GraphicsConfiguration.html - Javadoc – třída DisplayMode
http://docs.oracle.com/javase/7/docs/api/java/awt/DisplayMode.html - Lesson: Full-Screen Exclusive Mode API
http://docs.oracle.com/javase/tutorial/extra/fullscreen/ - Full-Screen Exclusive Mode
http://docs.oracle.com/javase/tutorial/extra/fullscreen/exclusivemode.html - Display Mode
http://docs.oracle.com/javase/tutorial/extra/fullscreen/displaymode.html - Using the Full-Screen Exclusive Mode API in Java
http://www.developer.com/java/other/article.php/3609776/Using-the-Full-Screen-Exclusive-Mode-API-in-Java.htm - Java quick guide: JVM Instruction Set (tabulka všech instrukcí JVM)
http://www.mobilefish.com/tutorials/java/java_quickguide_jvm_instruction_set.html - The JVM Instruction Set
http://mpdeboer.home.xs4all.nl/scriptie/node14.html - MultiMedia eXtensions
http://softpixel.com/~cwright/programming/simd/mmx.phpi - SSE (Streaming SIMD Extentions)
http://www.songho.ca/misc/sse/sse.html - Timothy A. Chagnon: SSE and SSE2
http://www.cs.drexel.edu/~tc365/mpi-wht/sse.pdf - Intel corporation: Extending the Worldr's Most Popular Processor Architecture
http://download.intel.com/technology/architecture/new-instructions-paper.pdf - SIMD architectures:
http://arstechnica.com/old/content/2000/03/simd.ars/ - GC safe-point (or safepoint) and safe-region
http://xiao-feng.blogspot.cz/2008/01/gc-safe-point-and-safe-region.html - Safepoints in HotSpot JVM
http://blog.ragozin.info/2012/10/safepoints-in-hotspot-jvm.html - Java theory and practice: Synchronization optimizations in Mustang
http://www.ibm.com/developerworks/java/library/j-jtp10185/ - How to build hsdis
http://hg.openjdk.java.net/jdk7/hotspot/hotspot/file/tip/src/share/tools/hsdis/README - Java SE 6 Performance White Paper
http://www.oracle.com/technetwork/java/6-performance-137236.html - Lukas Stadler's Blog
http://classparser.blogspot.cz/2010/03/hsdis-i386dll.html - How to build hsdis-amd64.dll and hsdis-i386.dll on Windows
http://dropzone.nfshost.com/hsdis.htm - PrintAssembly
https://wikis.oracle.com/display/HotSpotInternals/PrintAssembly - The Java Virtual Machine Specification: 3.14. Synchronization
http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-3.html#jvms-3.14 - The Java Virtual Machine Specification: 8.3.1.4. volatile Fields
http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.1.4 - The Java Virtual Machine Specification: 17.4. Memory Model
http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4 - The Java Virtual Machine Specification: 17.7. Non-atomic Treatment of double and long
http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.7 - Open Source ByteCode Libraries in Java
http://java-source.net/open-source/bytecode-libraries - ASM Home page
http://asm.ow2.org/ - Seznam nástrojů využívajících projekt ASM
http://asm.ow2.org/users.html - ObjectWeb ASM (Wikipedia)
http://en.wikipedia.org/wiki/ObjectWeb_ASM - Java Bytecode BCEL vs ASM
http://james.onegoodcookie.com/2005/10/26/java-bytecode-bcel-vs-asm/ - BCEL Home page
http://commons.apache.org/bcel/ - Byte Code Engineering Library (před verzí 5.0)
http://bcel.sourceforge.net/ - Byte Code Engineering Library (verze >= 5.0)
http://commons.apache.org/proper/commons-bcel/ - BCEL Manual
http://commons.apache.org/bcel/manual.html - Byte Code Engineering Library (Wikipedia)
http://en.wikipedia.org/wiki/BCEL - BCEL Tutorial
http://www.smfsupport.com/support/java/bcel-tutorial!/ - Bytecode Engineering
http://book.chinaunix.net/special/ebook/Core_Java2_Volume2AF/0131118269/ch13lev1sec6.html - Bytecode Outline plugin for Eclipse (screenshoty + info)
http://asm.ow2.org/eclipse/index.html - Javassist
http://www.jboss.org/javassist/ - Byteman
http://www.jboss.org/byteman - Java programming dynamics, Part 7: Bytecode engineering with BCEL
http://www.ibm.com/developerworks/java/library/j-dyn0414/ - The JavaTM Virtual Machine Specification, Second Edition
http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html - The class File Format
http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html - javap – The Java Class File Disassembler
http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javap.html - javap-java-1.6.0-openjdk(1) – Linux man page
http://linux.die.net/man/1/javap-java-1.6.0-openjdk - Using javap
http://www.idevelopment.info/data/Programming/java/miscellaneous_java/Using_javap.html - Examine class files with the javap command
http://www.techrepublic.com/article/examine-class-files-with-the-javap-command/5815354 - aspectj (Eclipse)
http://www.eclipse.org/aspectj/ - Aspect-oriented programming (Wikipedia)
http://en.wikipedia.org/wiki/Aspect_oriented_programming - AspectJ (Wikipedia)
http://en.wikipedia.org/wiki/AspectJ - EMMA: a free Java code coverage tool
http://emma.sourceforge.net/ - Cobertura
http://cobertura.sourceforge.net/ - jclasslib bytecode viewer
http://www.ej-technologies.com/products/jclasslib/overview.html