Obsah
1. Pohled pod kapotu JVM – double buffering v praxi (dokončení)
2. První demonstrační příklad: vykreslování do objektu typu Canvas bez použití double bufferingu
3. Úprava příkladu takovým způsobem, aby se vykreslování provádělo do zadního bufferu
4. Druhý demonstrační příklad: vykreslování do objektu typu Canvas s využitím double bufferingu
5. Double buffering a exkluzivní celoobrazovkové grafické režimy
6. Nastavení celoobrazovkového grafického režimu a vytvoření zadního bufferu
7. Třetí demonstrační příklad: double buffering v celoobrazovkovém grafickém režimu
8. Repositář se zdrojovými kódy dnešních demonstračních příkladů
1. Pohled pod kapotu JVM – double buffering v praxi (dokončení)
V předchozí části seriálu o programovacím jazyce Java i o virtuálním stroji Javy jsme si řekli, jakým způsobem je double buffering použit v knihovně Swing a jak je možné v případě potřeby využití zadního bufferu vypnout. Dnes si na několika demonstračních příkladech ukážeme využití double bufferingu při výběru knihovny AWT namísto Swing a při vykreslování grafiky s využitím celoobrazovkových exkluzivních grafických režimů (kde lze taktéž využít možností nabízených knihovnou AWT). Ihned na začátku tohoto článku je možná vhodné si připomenout základní rozdíly mezi knihovnami AWT (Abstract Window Toolkit) a Swing. Knihovna AWT se snaží využívat nativní ovládací prvky (widgety), takže na tuto knihovnu lze pohlížet jako na určitý most mezi Javou a nativními toolkity. To například znamená, že vzhled ovládacích prvků i jejich chování je možné měnit jen v určitých (relativně malých) mezích a současně se vzhled aplikace může na různých platformách odlišovat (což někdy může být vhodné chování).
Naproti tomu jsou v knihovně Swing všechny komponenty (ovládací prvky atd.) vykreslovány s využitím metod naprogramovaných v Javě s tím, že nízkoúrovňové kreslicí operace jsou implementovány v nativních funkcích resp. voláním metod Java2D (teprve ty interně volají nativní metody). Díky tomu je možné do značné míry měnit vzhled i chování všech ovládacích prvků, zajistit stejný vzhled aplikace na všech systémech apod. Navíc je při vykreslování všech komponent implicitně používán double buffering, což je problematika, kterou jsme se podrobněji zabývali minule.
Zatímco většina javovských aplikací s GUI již využívá možnosti knihovny Swing, je při návrhu hry či jiné graficky náročné aplikace, která využívá celoobrazovkové režimy, situace poněkud odlišná, protože zde většinou nevyužijeme všech vlastností Swingu a navíc může být použití swingovských komponent vykreslovaných s využitím kódu napsaného v Javě zbytečně limitující a pomalé. Proto si dnes ukážeme, jak lze využít komponenty java.awt.Frame a java.awt.Canvas pro tvorbu základní kostry grafického subsystému hry.
2. První demonstrační příklad: vykreslování do objektu typu Canvas bez použití double bufferingu
První demonstrační příklad je velmi jednoduchý, ovšem poměrně dobře nám ukazuje některé základní vlastnosti knihovny AWT. Po spuštění tohoto příkladu se vytvoří nové okno představované instancí třídy odvozené od třídy java.awt.Frame. Do okna je vložen prvek typu java.awt.Canvas, resp. přesněji řečeno se opět jedná o instanci třídy odvozené od java.awt.Canvas. Důležité je, že v odvozené třídě došlo k překrytí metody public void paint(Graphics g), díky čemuž je možné na Canvas (kreslicí plátno) vykreslovat libovolný obrazec. Zde však narazíme na jednu potenciálně nepříjemnou vlastnost – vzhledem k tomu, že se v knihovně AWT implicitně nepoužívá double buffering, bude na pomalejších počítačích viditelné pomalé překreslování obrazce, což je nejlépe patrné při postupném zvětšování a/nebo zmenšování okna (rámce). Pokud je překreslování na vašem počítači dostatečně rychlé, je možné nežádoucí grafické efekty jednoduše vyvolat tak, že se změní krok vykreslovací smyčky z hodnoty 0.005 na hodnotu 0.001 či ještě nižší hodnotu. Aplikace se jednoduše ukončí stiskem tlačítka myši kamkoli na kreslicí plochu.
import java.awt.Canvas; import java.awt.Color; import java.awt.Dimension; import java.awt.Frame; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; /** * Test vykreslovani na objekt typu Canvas v pripade, ze neni * povoleno pouzivani double bufferingu. * * @author Pavel Tisnovsky */ public class DoubleBufferTest1 extends Frame { /** * Generated serial version UID. */ private static final long serialVersionUID = 6423061537074933572L; /** * Kreslici plocha - Canvas. */ private Drawing1 drawing = new Drawing1(); /** * Vytvoreni okna a pridani kresby do tohoto okna. */ private void run() { // pri postupnem zvetsovani okna bude prosvitat modre pozadi this.setBackground(Color.BLUE); // potrebujeme aktivni okraje okna this.setUndecorated(false); // pridani kresby do okna this.add(this.drawing); this.pack(); this.setVisible(true); } /** * Spusteni testu. */ public static void main(String[] args) { new DoubleBufferTest1().run(); } } /** * Kreslici plocha odvozena od objektu typu Canvas. * * @author Pavel Tisnovsky */ class Drawing1 extends Canvas { /** * Generated serial version UID. */ private static final long serialVersionUID = -3936987144006140956L; /** * Konstruktor - nastaveni zakladnich parametru kreslici plochy. */ public Drawing1() { this.setBackground(Color.WHITE); this.setPreferredSize(new Dimension(800, 600)); addCustomMouseListener(); } /** * Mouse listener zajisti ukonceni programu po kliku na kreslici plochu. */ private void addCustomMouseListener() { addMouseListener(new MouseListener() { public void mouseClicked(MouseEvent e) { System.exit(0); } public void mousePressed(MouseEvent e) { // prazdny blok } public void mouseReleased(MouseEvent e) { // prazdny blok } public void mouseEntered(MouseEvent e) { // prazdny blok } public void mouseExited(MouseEvent e) { // prazdny blok }}); } @Override public void paint(Graphics g) { final Graphics2D graphics2d = (Graphics2D)g; graphics2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); final int width = this.getWidth(); final int height = this.getHeight(); final double radius = Math.min(width, height) / 3.0; // casove narocne vykresleni obrazce // (na rychlejsich pocitacich lze zmenit krok 0.005 na 0.001) int xold=0, yold=0; for (double d = 0; d < Math.PI *2*7; d += 0.005) { int x = (int)(width / 2 + radius * Math.cos(d) + radius/2 * Math.sin(d/7)); int y = (int)(height / 2 + radius * Math.sin(d) + radius/2 * Math.cos(d/7)); graphics2d.setColor(Color.BLACK); if (d>0) { graphics2d.drawLine(xold, yold, x, y); } xold = x; yold = y; } } }
3. Úprava příkladu takovým způsobem, aby se vykreslování provádělo do zadního bufferu
Nežádoucí postupné vykreslování obrazce je možné jednoduše před uživateli skrýt takovým způsobem, že se obrazec nejprve vykreslí do neviditelného zadního bufferu a teprve poté se buď přesune do viditelného předního bufferu, popř. dojde k velmi rychlému přepnutí mezi předním a zadním bufferem. Pro explicitní řízení double bufferingu se používá třída BufferStrategy, o níž jsme se zmínili minule. Připomeňme si tedy, že se instance této třídy vytvoří zavoláním java.awt.Canvas.createBufferStrategy(int) popř. (což je asi méně časté) zavoláním metody java.awt.Window.createBufferStrategy(int). Celočíselná hodnota, která se těmto metodám předává, reprezentuje celkový počet bufferů. Přitom je zaručeno, že se daný počet bufferů skutečně vytvoří, ale v závislosti na možnostech konkrétního počítače nemusí být podporován page flipping a dokonce ani akcelerované přenášení obsahu zadního bufferu do bufferu předního.
Jakmile je korektně nastaven double buffering, změní se i vykreslovací rutina, protože ta již nebude provádět vykreslování přímo na java.awt.Canvas s využitím objektu typu Graphics předaného metodě public void paint(), ale do zadního bufferu:
BufferStrategy bufferStrategy = canvas.getBufferStrategy(); while (!done) { Graphics graphics; try { graphics = bufferStrategy.getDrawGraphics(); ... zde se provádí vykreslování ... ... s využitím objektu "graphics" ... } finally { graphics.dispose(); } bufferStrategy.show(); }
V našem konkrétním případě dojde ve vykreslovací rutině k následující změně (zde je použit formát unifikovaného diffu):
--- DoubleBufferTest1.java 2014-01-05 21:21:39.000000000 +0100 +++ DoubleBufferTest2.java 2014-01-05 21:21:50.000000000 +0100 @@ -1,6 +1,9 @@ @Override public void paint(Graphics g) { - final Graphics2D graphics2d = (Graphics2D)g; + // ziskat objekt typu Graphics2D pro zadni buffer + BufferStrategy bufferStrategy = getBufferStrategy(); + final Graphics2D graphics2d = (Graphics2D)bufferStrategy.getDrawGraphics(); + graphics2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); final int width = this.getWidth(); final int height = this.getHeight(); @@ -18,4 +21,7 @@ xold = x; yold = y; } + graphics2d.dispose(); + // prohozeni bufferu a/nebo prekresleni zadniho bufferu do bufferu predniho + bufferStrategy.show(); }
Grafické zvýraznění rozdílu mezi oběma vykreslovacími rutinami:
4. Druhý demonstrační příklad: vykreslování do objektu typu Canvas s využitím double bufferingu
Dnešní druhý demonstrační příklad již při vykreslování do objektu typu java.awt.Canvas využívá double buffering. Princip práce vykreslovací rutiny jsme si vysvětlili v předchozí kapitole, ovšem důležitá je taktéž rutina použitá pro vytvoření předního a zadního bufferu. Tato rutina je součástí metody DoubleBufferTest2.run(), v níž se konfigurace bufferů provádí až poté, kdy je objekt odvozený od java.awt.Canvas vložen do okna/rámce. To je důležité, protože v případě, že by objekt java.awt.Canvas ještě nebyl vložen do jiné komponenty, došlo by k běhové chybě (což si můžete snadno otestovat):
/** * Vytvoreni okna a pridani kresby do tohoto okna. */ private void run() { // pri postupnem zvetsovani okna bude prosvitat modre pozadi this.setBackground(Color.BLUE); // potrebujeme aktivni okraje okna this.setUndecorated(false); // pridani kresby do okna this.add(this.drawing); this.pack(); // nastaveni double bufferingu this.drawing.createBufferStrategy(2); this.setVisible(true); }
Následuje výpis zdrojového kódu dnešního druhého demonstračního příkladu:
import java.awt.Canvas; import java.awt.Color; import java.awt.Dimension; import java.awt.Frame; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.image.BufferStrategy; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; /** * Test vykreslovani na objekt typu Canvas v pripade, ze je * povoleno pouzivani double bufferingu. * * @author Pavel Tisnovsky */ public class DoubleBufferTest2 extends Frame { /** * Generated serial version UID. */ private static final long serialVersionUID = 6423061537074933572L; /** * Kreslici plocha - Canvas. */ private Drawing2 drawing = new Drawing2(); /** * Vytvoreni okna a pridani kresby do tohoto okna. */ private void run() { // pri postupnem zvetsovani okna bude prosvitat modre pozadi this.setBackground(Color.BLUE); // potrebujeme aktivni okraje okna this.setUndecorated(false); // pridani kresby do okna this.add(this.drawing); this.pack(); // nastaveni double bufferingu this.drawing.createBufferStrategy(2); this.setVisible(true); } /** * Spusteni testu. */ public static void main(String[] args) { new DoubleBufferTest2().run(); } } /** * Kreslici plocha odvozena od objektu typu Canvas. * * @author Pavel Tisnovsky */ class Drawing2 extends Canvas { /** * Generated serial version UID. */ private static final long serialVersionUID = -3936987144006140956L; /** * Konstruktor - nastaveni zakladnich parametru kreslici plochy. */ public Drawing2() { this.setBackground(Color.WHITE); this.setPreferredSize(new Dimension(800, 600)); addCustomMouseListener(); } /** * Mouse listener zajisti ukonceni programu po kliku na kreslici plochu. */ private void addCustomMouseListener() { addMouseListener(new MouseListener() { public void mouseClicked(MouseEvent e) { System.exit(0); } public void mousePressed(MouseEvent e) { // prazdny blok } public void mouseReleased(MouseEvent e) { // prazdny blok } public void mouseEntered(MouseEvent e) { // prazdny blok } public void mouseExited(MouseEvent e) { // prazdny blok }}); } @Override public void paint(Graphics g) { // ziskat objekt typu Graphics2D pro zadni buffer BufferStrategy bufferStrategy = getBufferStrategy(); final Graphics2D graphics2d = (Graphics2D)bufferStrategy.getDrawGraphics(); graphics2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); final int width = this.getWidth(); final int height = this.getHeight(); final double radius = Math.min(width, height) / 3.0; // casove narocne vykresleni obrazce // (na rychlejsich pocitacich lze zmenit krok 0.005 na 0.001) int xold=0, yold=0; for (double d = 0; d < Math.PI *2*7; d += 0.005) { int x = (int)(width / 2 + radius * Math.cos(d) + radius/2 * Math.sin(d/7)); int y = (int)(height / 2 + radius * Math.sin(d) + radius/2 * Math.cos(d/7)); graphics2d.setColor(Color.BLACK); if (d>0) { graphics2d.drawLine(xold, yold, x, y); } xold = x; yold = y; } graphics2d.dispose(); // prohozeni bufferu a/nebo prekresleni zadniho bufferu do bufferu predniho bufferStrategy.show(); } }
5. Double buffering a exkluzivní celoobrazovkové grafické režimy
Velmi časté je použití programově řízeného double bufferingu v těch případech, kdy aplikace (většinou nějaká hra) provádí vykreslování na celou obrazovku, tj. při využití exkluzivních celoobrazovkových grafických režimů. V předchozích částech tohoto seriálu jsme si již ukázali, jakým způsobem je možné provést přepnutí do celoobrazovkového grafického režimu a jak lze v případě potřeby využít rastrové obrázky typu VolatileImage namísto obecně pomalejších bitmap typu BufferedImage. Teoreticky je možné VolatileImage použít ve funkci zadního bufferu, ovšem většinou bývá výhodnější se spolehnout na to, že grafický subsystém počítače umožní v celoobrazovkovém režimu použít přední i zadní buffer s tím, že bude podporovat operaci typu flip pro prohození funkcí obou bufferů.
Proč je použití flip mnohem výhodnější než volání operace typu BitBlt pro VolatileImage, je zřejmé – v prvním případě se jedná o jednoduchou operaci, při níž se prakticky nepřenáší žádná data, kdežto v případě druhém je nutné přenést všechny pixely zdrojového obrázku do bufferu, a to mnohdy několikrát (20×) za sekundu. Tento přenos se sice v ideálním případě provádí pouze v rámci obrazové paměti (tudíž akcelerovaně), i tak se však z hlediska celkového výkonu a popř. i energetických požadavků (notebooky tablety atd.) nejedná o ideální způsob, jak implementovat double buffering.
6. Nastavení celoobrazovkového grafického režimu a vytvoření zadního bufferu
Nastavení celoobrazovkového grafického režimu je poměrně snadné, protože můžeme využít znalostí, o nichž jsme se v tomto seriálu již zmínili. Následující metoda nejprve nastaví parametry vybraného okna/rámce tak, aby bylo zobrazeno přes celou obrazovku (bez okrajů) a následně vybere a nastaví grafický režim s požadovaným rozlišením GRAPHICS_MODE_WIDTH×GRAPHICS_MODE_HEIGHT a libovolnou bitovou (barvovou) hloubkou:
/** * Nastaveni grafickeho rezimu. */ private void setFullScreenMode(Frame frame) { GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice graphicsDevice = env.getDefaultScreenDevice(); graphicsDevice.setFullScreenWindow(frame); DisplayMode selectedDisplayMode = null; // pokusime se vyhledat pozadovany graficky rezim. for (DisplayMode displayMode : graphicsDevice.getDisplayModes()) { if (displayMode.getWidth() == GRAPHICS_MODE_WIDTH && displayMode.getHeight() == GRAPHICS_MODE_HEIGHT) { selectedDisplayMode = displayMode; break; } } graphicsDevice.setDisplayMode(selectedDisplayMode); }
Při použití celoobrazovkového režimu navíc není ani nutné využívat objekt typu java.awt.Canvas. Namísto toho je vykreslování možné provádět přímo na rámec. Vzhledem k tomu, že se vůbec nepoužívá callback metoda public void paint(), je vhodné před zobrazením rámce zavolat metodu Frame.setIgnoreRepaint(true). Vlastní vykreslení obrazce je posléze „vynuceno“ programovým prohozením funkce předního a zadního bufferu:
/** * Prekresleni obsahu ramce. */ private void repaintFrame(Frame frame, double angle) { // ziskat objekt typu Graphics2D pro zadni buffer BufferStrategy bufferStrategy = frame.getBufferStrategy(); final Graphics2D graphics2d = (Graphics2D) bufferStrategy.getDrawGraphics(); graphics2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON); final int width = frame.getWidth(); final int height = frame.getHeight(); final double radius = Math.min(width, height) / 3.0; // casove narocne vykresleni obrazce // (na rychlejsich pocitacich lze zmenit krok 0.005 na 0.001) int xold = 0, yold = 0; for (double d = 0; d < Math.PI * 2 * 7; d += 0.005) { int x = (int) (width / 2 + radius * Math.cos(d) + radius / 2 * Math.sin(d / 7 + angle)); int y = (int) (height / 2 + radius * Math.sin(d) + radius / 2 * Math.cos(d / 7 + angle)); graphics2d.setColor(Color.BLACK); if (d > 0) { graphics2d.drawLine(xold, yold, x, y); } xold = x; yold = y; } graphics2d.dispose(); // prohozeni bufferu a/nebo prekresleni zadniho bufferu do bufferu // predniho bufferStrategy.show(); }
7. Třetí demonstrační příklad: double buffering v celoobrazovkovém grafickém režimu
V dnešním třetím a současně i posledním demonstračním příkladu jsou využity principy vysvětlené v předchozích dvou kapitolách. Po spuštění aplikace je vytvořeno okno (rámec), následně jsou skryty okraje tohoto okna (dekorace) a posléze je nastaven celoobrazovkový grafický režim a obsah okna je zvětšen tak, aby obsáhl celou plochu obrazovky. Po těchto operacích je pro toto okno vytvořen přední a zadní buffer a poté se ve smyčce volá překreslovací rutina, která postupně (bez mazání předního či zadního bufferu) postupně dokresluje obrazec do následující podoby:
Poté je aplikace automaticky ukončena. Úplný zdrojový kód tohoto příkladu je vypsán pod tímto odstavcem:
import java.awt.Color; import java.awt.DisplayMode; import java.awt.Frame; import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.RenderingHints; import java.awt.image.BufferStrategy; /** * Test vykreslovani v celoobrazovkovem grafickem rezimu pri povoleni * double bufferingu. * * @author Pavel Tisnovsky */ public class DoubleBufferTest3 { /** * Generated serial version UID. */ private static final long serialVersionUID = 6423061537074933572L; /** * Horizontalni rozliseni pozadovaneho grafickeho rezimu. */ private static final int GRAPHICS_MODE_WIDTH = 1024; /** * Vertikalni rozliseni pozadovaneho grafickeho rezimu. */ private static final int GRAPHICS_MODE_HEIGHT = 768; /** * Vytvoreni okna a pridani kresby do tohoto okna. */ private void run() { Frame frame = createFrame(); // nastaveni celoobrazovkoveho rezimu setFullScreenMode(frame); // vytvoreni zadniho bufferu frame.createBufferStrategy(2); // prekresleni ramce - jednoducha animace for (double angle = 0.0; angle < 1; angle += 0.1) { repaintFrame(frame, angle); } // ukonceni aplikace exitFromFullScreenMode(); System.exit(0); } /** * Vytvoreni ramce a nastaveni jeho vlastnosti. * @return */ private Frame createFrame() { Frame frame = null; GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice graphicsDevice = env.getDefaultScreenDevice(); GraphicsConfiguration graphicsConfiguration = graphicsDevice.getDefaultConfiguration(); // vytvoreni ramce frame = new Frame(graphicsConfiguration); // pozadi ramce frame.setBackground(Color.WHITE); // bez aktivnich okraju okna frame.setUndecorated(true); // nechceme, aby system sam okno prekreslil frame.setIgnoreRepaint(true); return frame; } /** * Nastaveni grafickeho rezimu. */ private void setFullScreenMode(Frame frame) { GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice graphicsDevice = env.getDefaultScreenDevice(); graphicsDevice.setFullScreenWindow(frame); DisplayMode selectedDisplayMode = null; // pokusime se vyhledat pozadovany graficky rezim. for (DisplayMode displayMode : graphicsDevice.getDisplayModes()) { if (displayMode.getWidth() == GRAPHICS_MODE_WIDTH && displayMode.getHeight() == GRAPHICS_MODE_HEIGHT) { selectedDisplayMode = displayMode; break; } } graphicsDevice.setDisplayMode(selectedDisplayMode); } /** * Ukonceni grafickeho rezimu. */ private void exitFromFullScreenMode() { GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice graphicsDevice = env.getDefaultScreenDevice(); graphicsDevice.setFullScreenWindow(null); } /** * Prekresleni obsahu ramce. */ private void repaintFrame(Frame frame, double angle) { // ziskat objekt typu Graphics2D pro zadni buffer BufferStrategy bufferStrategy = frame.getBufferStrategy(); final Graphics2D graphics2d = (Graphics2D) bufferStrategy.getDrawGraphics(); graphics2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON); final int width = frame.getWidth(); final int height = frame.getHeight(); final double radius = Math.min(width, height) / 3.0; // casove narocne vykresleni obrazce // (na rychlejsich pocitacich lze zmenit krok 0.005 na 0.001) int xold = 0, yold = 0; for (double d = 0; d < Math.PI * 2 * 7; d += 0.005) { int x = (int) (width / 2 + radius * Math.cos(d) + radius / 2 * Math.sin(d / 7 + angle)); int y = (int) (height / 2 + radius * Math.sin(d) + radius / 2 * Math.cos(d / 7 + angle)); graphics2d.setColor(Color.BLACK); if (d > 0) { graphics2d.drawLine(xold, yold, x, y); } xold = x; yold = y; } graphics2d.dispose(); // prohozeni bufferu a/nebo prekresleni zadniho bufferu do bufferu // predniho bufferStrategy.show(); } /** * Spusteni testu. */ public static void main(String[] args) { new DoubleBufferTest3().run(); } }
8. Repositář se zdrojovými kódy dnešních demonstračních příkladů
Následují v tomto seriálu již tradiční odkazy na zdrojové kódy uložené do Mercurial repositáře. V tabulce zobrazené pod tímto odstavcem najdete linky na prozatím nejnovější verze všech tří dnes popsaných demonstračních příkladů:
# | Zdrojový soubor/skript | Umístění souboru v repositáři |
---|---|---|
1 | DoubleBufferTest1.java | http://icedtea.classpath.org/people/ptisnovs/jvm-tools/file/8754588b4129/jvm/gfx/DoubleBufferTest1.java |
2 | DoubleBufferTest2.java | http://icedtea.classpath.org/people/ptisnovs/jvm-tools/file/8754588b4129/jvm/gfx/DoubleBufferTest2.java |
3 | DoubleBufferTest3.java | http://icedtea.classpath.org/people/ptisnovs/jvm-tools/file/bec273a159be/jvm/gfx/DoubleBufferTest3.java |
9. Odkazy na Internetu
- Class java.awt.Frame (JDK7)
http://docs.oracle.com/javase/7/docs/api/java/awt/Frame.html - Class java.awt.Canvas (JDK7)
http://docs.oracle.com/javase/7/docs/api/java/awt/Canvas.html - Class java.awt.image.BufferStrategy (JDK6)
http://docs.oracle.com/javase/6/docs/api/java/awt/image/BufferStrategy.html - Class java.awt.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