Obsah
1. Pohled pod kapotu JVM – exkluzivní celoobrazovkové grafické režimy
2. Zjištění informací o nainstalovaných grafických kartách
3. Zjištění informací o všech dostupných grafických režimech
4. První demonstrační příklad: výpis informací o všech dostupných grafických režimech
5. Ukázky výstupu prvního demonstračního příkladu
6. Nastavení celoobrazovkového grafického režimu
8. Problematika tvorby a vykreslování bitmap podruhé
9. Repositář se zdrojovými soubory obou demonstračních příkladů
1. Pohled pod kapotu JVM – exkluzivní celoobrazovkové grafické režimy
V dnešní části seriálu o programovacím jazyce Java i o virtuálním stroji Javy se seznámíme s API Javy, které je určeno pro „exkluzivní“ práci s takzvanými celoobrazovkovými grafickými režimy. I přes tento poněkud honosný název jsou třídy, rozhraní a metody nabízené tímto API poměrně snadno pochopitelné i použitelné. Základem tohoto rozhraní jsou třídy a metody umožňující zjistit informace o všech dostupných grafických režimech. Vybraný grafický režim je následně možné zapnout a poté využívat „exkluzivní“ přístup na obrazovku bez toho, aby se musela aplikace či nějaká grafická knihovna zabývat a zdržovat zobrazováním oken jiných aplikací. V celoobrazovkových režimech je navíc možné vykreslovat bitmapy (rastrové obrázky) obecně rychleji, než by tomu bylo při práci v okně (rámci). Rychlejšího vykreslování je dosaženo použitím funkcí grafických akcelerátorů a taktéž tím, že bitmapy, s nimiž se často pracuje, mohou být uloženy přímo v obrazové paměti a nikoli v hlavní paměti (potom by bylo nutné neustále bitmapy přenášet a tím zbytečně zatěžovat CPU).
Dnes popisované API navíc umožňuje rozdělení obrazové paměti (framebufferu) na takzvaný přední a zadní buffer (front buffer, back buffer) s tím, že vykreslování lze provádět do neviditelného zadního bufferu bez toho, aby uživatel viděl jednotlivé fáze vykreslování. Ve chvíli, kdy je vykreslení celého obrázku v zadním bufferu dokončeno, se úlohy předního a zadního bufferu jednoduše prohodí, což je opět operace podporovaná všemi grafickými akcelerátory. V souvislosti s framebufferem je na tomto místě vhodné zmínit i třídu java.awt.image.VolatileImage sloužící k uložení bitmapy v obrazové paměti s tím, že obsah této bitmapy může (grafický) systém kdykoli změnit (přesněji řečeno poškodit), což znamená nutnost jeho následné obnovy. Mohlo by se možná zdát, že tato třída nebude mít oproti BufferedImage žádnou výhodu, neboť programátorovi spíš přidává starosti, ovšem v některých případech je možné VolatileImage s výhodou využít, například při programování animací atd. Podrobněji se s touto zajímavou problematikou seznámíme příště.
2. Zjištění informací o nainstalovaných grafických kartách
V předchozí kapitole jsme si řekli, že rozhraní pro práci s exkluzivními celoobrazovkovými grafickými režimy nabízí v první řadě metody pro zjištění, které režimy lze vůbec na daném počítači využít. K získání těchto informací je nutné použít několik tříd. První třídou, kterou náš popis začne, je třída java.awt.GraphicsEnvironment, která programátorům vrací informace o možnostech a konfiguraci grafického prostředí Javy. Tato abstraktní třída obsahuje především statickou metodu getLocalGraphicsEnvironment() vracející jednu konkrétní instanci této třídy. To znamená, že běžným způsobem získání instance této třídy není volání konstruktoru (ten má modifikátor protected, tudíž ho ve skutečnosti ani volat nelze), ale následující příkaz:
GraphicsEnvironment graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment();
Jakmile jsme získali konkrétní instanci třídy GraphicsEnvironment, je možné například zjistit všechny použitelné fonty atd. Nás bude ale zajímat především informace o grafických režimech. Nejprve je nutné zjistit, jaké grafické karty jsou v systému nainstalovány. To zajistí následující příkaz vracející pole objektů typu java.awt.GraphicsDevice:
GraphicsDevice[] graphicsDevices = graphicsEnvironment.getScreenDevices();
O každé grafické kartě vrácené v poli můžeme získat podrobnější informace s využitím metod:
Metoda | Popis |
---|---|
GraphicsDevice.getAvailableAcceleratedMemory() | volná paměť pro alokaci bitmap, mnohdy vrací –1==nelze zjistit |
GraphicsDevice.isDisplayChangeSupported() | hodnota true když je podporována změna grafického režimu, popíšeme si níže, kdy lze volat |
GraphicsDevice.isFullScreenSuported() | hodnota true když lze zapnout vybraný celoobrazovkový režim |
GraphicsDevice.getType() | typ zařízení: měla by se vrátit hodnota TYPE_RASTER_SCREEN |
GraphicsDevice.getIDstring() | řetězec s identifikátorem grafické karty (liší se podle systému i JDK, obecně nepřenositelný údaj) |
Od JDK verze 1.7 lze navíc zjistit, zda je podporována průhlednost a/nebo průsvitnost pixelů. V závislosti na možnostech grafické karty je možné pracovat s plně průhlednými či naopak plně neprůhlednými pixely (WindowTranslucency.PERPIXEL_TRANSPARENT), bitmapou či oknem se zadanou průhledností (WindowTranslucency.TRANSLUCENT) či dokonce s pixely, z nichž každý může mít nastavenou jinou úroveň průhlednosti WindowTranslucency.PERPIXEL_TRANSLUCENT). Tato poslední možnost je nejpomalejší, takže se v mnoha hrách stejně využívají pouze bitmapy/okna s plně průhlednými a plně neprůhlednými pixely (WindowTranslucency.TRANSLUCENT):
Metoda | Popis |
---|---|
GraphicsDevice.isWindowTranslucencySupported(WindowTranslucency.PERPIXEL_TRANSPARENT | plně průhledné/neprůhledné pixely |
GraphicsDevice.isWindowTranslucencySupported(WindowTranslucency.TRANSLUCENT | průhlednost nastavená pro celou bitmapu/okno |
GraphicsDevice.isWindowTranslucencySupported(WindowTranslucency.PERPIXEL_TRANSLUCENT | průhlednost nastavená pro jednotlivé pixely |
3. Zjištění informací o všech dostupných grafických režimech
Pro přečtení informací o všech grafických režimech nabízených a podporovaných vybranou grafickou kartou se používá metoda GraphicsDevice.getDisplayModes(). Tato metoda vrací pole objektů typu java.awt.DisplayMode, což znamená, že všechny dostupné grafické režimy získáme příkazem:
DisplayMode[] modes = graphicsDevice.getDisplayModes();
Pro každý grafický režim lze přečíst tři základní informace: rozlišení (horizontální a vertikální počet pixelů), bitovou hloubku a obnovovací/snímkovou frekvenci. Kupodivu již nelze přečíst další informace, například o formátu uložení pixelů v obrazové paměti, skutečnou délku obrazového řádku atd. Navíc se v některých případech kvůli omezení možností grafického subsystému namísto skutečné bitové hloubky vrací hodnota –1 (jde o celočíselnou konstantu DisplayMode.BIT_DEPTH_MULTI). Podobně tomu je i v případě frekvence, kdy na některých systémech dostaneme namísto údaje v hertzích (jde o celočíselnou a tudíž mnohdy nepřesnou hodnotu) pouze nulovou konstantu (odpovídající DisplayMode.REFRESH_RATE_UNKNOWN):
Metoda | Popis |
---|---|
DisplayMode.getWidth() | horizontální rozlišení grafického režimu (počet viditelných pixelů na řádku) |
DisplayMode.getHeight() | vertikální rozlišení grafického režimu (počet viditelných obrazových řádků) |
DisplayMode.getBitDepth() | bitová hloubka popř. konstanta DisplayMode.BIT_DEPTH_MULTI |
DisplayMode.getRefreshRate() | snímková frekvence popř. konstanta DisplayMode.REFRESH_RATE_UNKNOWN |
4. První demonstrační příklad: výpis informací o všech dostupných grafických režimech
Všechny třídy a metody popsané ve druhé i ve třetí kapitole jsou využity v dnešním prvním demonstračním příkladu, který po svém spuštění vypíše na standardní výstup základní informace o grafické konfiguraci i o dostupných grafických režimech. Tento příklad je přeložitelný na JDK7, v případě použití starších JDK (od verze 1.4) se však budou hlásit chyby z toho důvodu, že třída java.awt.GraphicsDevice.WindowTranslucency není viditelná (resp. nemá modifikátor public). V tomto případě je nutné jak odstranit příslušný import, tak i trojici řádků zjišťujících dostupnost operací pro práci s průhlednými či průsvitnými pixely:
import java.awt.DisplayMode; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.GraphicsDevice.WindowTranslucency; /** * Vypis zakladnich vlastnosti grafickych zarizeni, ktere lze vyuzit primo * z Javy. */ public class GraphicsDevicesTest { /** * Vstupni bod do tohoto testu. */ public static void main(String[] args) { GraphicsDevice[] graphicsDevices = getScreenGraphicsDevices(); printInfoAboutEachGraphicsDevice(graphicsDevices); } /** * Ziska pole se vsemi dostupnymi grafickymi zarizenimi. * * @return pole se vsemi dostupnymi grafickymi zarizenimi */ private static GraphicsDevice[] getScreenGraphicsDevices() { GraphicsEnvironment graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice[] graphicsDevices = graphicsEnvironment.getScreenDevices(); return graphicsDevices; } /** * Vypise informaci o vsech grafickych zarizenich predanych v parametru * graphicsDevices. * * @param graphicsDevices * pole se vsemi dostupnymi grafickymi zarizenimi */ private static void printInfoAboutEachGraphicsDevice(GraphicsDevice[] graphicsDevices) { for (int j = 0; j < graphicsDevices.length; j++) { GraphicsDevice graphicsDevice = graphicsDevices[j]; printGraphicsDeviceInfo(graphicsDevice); } } /** * Vypise informaci o grafickem zarizeni predanem v parametru * graphicsDevice. * * @param graphicsDevice * objekt reprezentujici dostupne graficke zarizeni. */ private static void printGraphicsDeviceInfo(GraphicsDevice graphicsDevice) { System.out.println("Device ID: " + graphicsDevice.getIDstring()); System.out.println("Type: " + getDeviceType(graphicsDevice)); System.out.println("Accelerated memory size: " + graphicsDevice.getAvailableAcceleratedMemory()); System.out.println("Display change supported: " + graphicsDevice.isDisplayChangeSupported()); System.out.println("Full screen supported: " + graphicsDevice.isFullScreenSupported()); System.out.println("Transparency/translucency support:"); System.out.println(" Per pixel transparency: " + graphicsDevice.isWindowTranslucencySupported(WindowTranslucency.PERPIXEL_TRANSPARENT)); System.out.println(" Per pixel translucency: " + graphicsDevice.isWindowTranslucencySupported(WindowTranslucency.PERPIXEL_TRANSLUCENT)); System.out.println(" Per window translucency: " + graphicsDevice.isWindowTranslucencySupported(WindowTranslucency.TRANSLUCENT)); System.out.println("Graphics modes:"); DisplayMode[] modes = graphicsDevice.getDisplayModes(); printAvailableDisplayModes(modes); System.out.println(); } /** * Vrati typ grafickeho zarizeni. * * @param graphicsDevice * objekt reprezentujici dostupne graficke zarizeni. * @return typ zarizeni (textova reprezentace) */ private static String getDeviceType(GraphicsDevice graphicsDevice) { switch (graphicsDevice.getType()) { case GraphicsDevice.TYPE_RASTER_SCREEN: return "raster screen"; case GraphicsDevice.TYPE_PRINTER: return "printer"; case GraphicsDevice.TYPE_IMAGE_BUFFER: return "image buffer"; default: // nemelo by nastat return "???"; } } /** * Vypise dostupne graficke rezimy a jejich zakladni vlastnosti. * * @param modes pole s grafickymi rezimy pro dane zarizeni. */ private static void printAvailableDisplayModes(DisplayMode[] modes) { for (DisplayMode mode : modes) { final int width = mode.getWidth(); final int height = mode. getHeight(); final int bpp = mode.getBitDepth(); final int refreshRate = mode.getRefreshRate(); System.out.println(" " + width + "x" + height + "@" + bpp + " bpp\t(" + refreshRate + " Hz)"); } } }
5. Ukázky výstupu prvního demonstračního příkladu
Podívejme se nyní na výsledky získané po spuštění dnešního prvního demonstračního příkladu na několika počítačích vybavených různými operačními systémy a samozřejmě i rozdílnými grafickými kartami. Prvním počítačem je starobylý (více než desetiletý) notebook s Oracle JDK7 a neaktualizovaným :-) systémem Microsoft Windows XP vybavený čipsetem Intel 855 GME. Jak je z následujícího výpisu patrné, je maximální dostupné rozlišení nabízených grafických režimů v tomto případě limitováno fyzickým rozlišením displeje tohoto notebooku (1024×768 pixelů), stejně tak i maximální snímková frekvence (70 Hz):
Device ID: \Display0 Type: raster screen Accelerated memory size: -1 Display change supported: false Full screen supported: true Transparency/translucency support: Per pixel transparency: true Per pixel translucency: true Per window translucency: true Graphics modes: 320x200@8 bpp (70 Hz) 320x200@16 bpp (70 Hz) 320x200@32 bpp (70 Hz) 320x240@8 bpp (70 Hz) 320x240@16 bpp (70 Hz) 320x240@32 bpp (70 Hz) 400x300@8 bpp (70 Hz) 400x300@16 bpp (70 Hz) 400x300@32 bpp (70 Hz) 512x384@8 bpp (70 Hz) 512x384@16 bpp (70 Hz) 512x384@32 bpp (70 Hz) 640x480@8 bpp (60 Hz) 640x400@8 bpp (70 Hz) 800x600@8 bpp (60 Hz) 1024x768@8 bpp (60 Hz) 640x480@16 bpp (60 Hz) 800x600@16 bpp (60 Hz) 1024x768@16 bpp (60 Hz) 640x480@32 bpp (60 Hz) 800x600@32 bpp (60 Hz) 1024x768@32 bpp (60 Hz) 640x400@16 bpp (70 Hz) 640x400@32 bpp (70 Hz)
Zajímavé je, že v některých případech (typicky na Linuxu s X Window) se nevrátí kompletní informace o podporovaných grafických režimech, popř. se vrátí obecnější informace, než jakou by programátor mnohdy potřeboval znát. V následujícím příkladu se například nevrátila přesná informace o bitové hloubce, ale hodnota –1, která odpovídá již výše zmíněné konstantě BIT_DEPTH_MULTI. Jedná se o OpenJDK7 spuštěné na Fedoře 19:
Device ID: :0.0 Type: raster screen Accelerated memory size: -1 Display change supported: false Full screen supported: true Transparency/translucency support: Per pixel transparency: true Per pixel translucency: true Per window translucency: true Graphics modes: 1366x768@-1 bpp (60 Hz) 1024x768@-1 bpp (60 Hz) 800x600@-1 bpp (60 Hz) 800x600@-1 bpp (56 Hz) 640x480@-1 bpp (60 Hz)
Mnohé grafické karty nabízí v kombinaci se správným typem monitoru mnohem větší množství grafických režimů, od režimů s nízkým rozlišením, které dnes mají spíše historický význam (ale může je využít například DOSBox), až po režimy se středním a vysokým (HD) rozlišením. Povšimněte si, že některé grafické režimy jsou nabízeny ve více variantách, které se liší barevnou hloubkou a/nebo obnovovací frekvencí (OpenJDK6 na Debianu a Ubuntu):
Device ID: :0.0 Type: raster screen Accelerated memory size: -1 Display change supported: false Full screen supported: true Transparency/translucency support: Graphics modes: 1280x1024@-1 bpp (50 Hz) 1280x1024@-1 bpp (51 Hz) 1280x960@-1 bpp (52 Hz) 1152x864@-1 bpp (53 Hz) 1152x864@-1 bpp (54 Hz) 1152x864@-1 bpp (55 Hz) 1152x864@-1 bpp (56 Hz) 1024x768@-1 bpp (57 Hz) 1024x768@-1 bpp (58 Hz) 1024x768@-1 bpp (59 Hz) 960x600@-1 bpp (60 Hz) 960x540@-1 bpp (61 Hz) 840x525@-1 bpp (62 Hz) 840x525@-1 bpp (63 Hz) 840x525@-1 bpp (64 Hz) 832x624@-1 bpp (65 Hz) 800x600@-1 bpp (66 Hz) 800x600@-1 bpp (67 Hz) 800x600@-1 bpp (68 Hz) 800x600@-1 bpp (69 Hz) 800x600@-1 bpp (70 Hz) 800x600@-1 bpp (71 Hz) 800x512@-1 bpp (72 Hz) 720x450@-1 bpp (73 Hz) 680x384@-1 bpp (74 Hz) 680x384@-1 bpp (75 Hz) 640x512@-1 bpp (76 Hz) 640x512@-1 bpp (77 Hz) 640x480@-1 bpp (78 Hz) 640x480@-1 bpp (79 Hz) 640x480@-1 bpp (80 Hz) 640x480@-1 bpp (81 Hz) 576x432@-1 bpp (82 Hz) 576x432@-1 bpp (83 Hz) 576x432@-1 bpp (84 Hz) 576x432@-1 bpp (85 Hz) 512x384@-1 bpp (86 Hz) 512x384@-1 bpp (87 Hz) 512x384@-1 bpp (88 Hz) 416x312@-1 bpp (89 Hz) 400x300@-1 bpp (90 Hz) 400x300@-1 bpp (91 Hz) 400x300@-1 bpp (92 Hz) 400x300@-1 bpp (93 Hz) 320x240@-1 bpp (94 Hz) 320x240@-1 bpp (95 Hz) 320x240@-1 bpp (96 Hz)
6. Nastavení celoobrazovkového grafického režimu
Pozorné čtenáře pravděpodobně překvapilo, že na všech třech testovaných počítačích zobrazil dnešní první demonstrační příklad zprávu:
Display change supported: false
Tato zpráva vlastně znamená, že dané grafické zařízení (grafická karta) zdánlivě nepodporuje přepínání a nastavování celoobrazovkových grafických režimů, což je zajisté podivné, protože tuto funkci provádí prakticky každá hra. Ve skutečnosti je ale chování metody GraphicsDevice.isDisplayChangeSupported() závislé na tom, zda je nastaven celoobrazovkový režim či nikoli. Pokud celoobrazovkový režim nastavený není (což je výchozí konfigurace), vrací metoda GraphicsDevice.isDisplayChangeSupported() hodnotu false, nezávisle na skutečných možnostech grafického akcelerátoru. Celoobrazovkový režim se nastavuje (resp. povoluje) metodou GraphicsDevice.setFullScreenWindow(), které se musí předat objekt typu java.awt.Window, což je typicky instance třídy java.awt.Frame. Toto okno/rámec následně získá rozměry grafického režimu, který bude možné následně přepnout:
Frame frame = new Frame(); graphicsDevice.setFullScreenWindow(frame); graphicsDevice.setDisplayMode(selectedDisplayMode);
Celoobrazovkový režim je následně možné vypnout opětovným zavoláním metody GraphicsDevice.setFullScreenWindow(), tentokrát se ovšem namísto objektu typu java.awt.Window předává hodnota null:
graphicsDevice.setFullScreenWindow(null);
Shrňme si nyní, jaké metody je nutné použít pro nastavení popř. pro vypnutí vybraného grafického celoobrazovkového režimu:
Metoda | Popis |
---|---|
GraphicsDevice.setFullScreenWindow(Window) | povolení celoobrazovkového režimu |
GraphicsDevice.setFullScreenWindow(null) | vypnutí celoobrazovkového režimu |
GraphicsDevice.setDisplayMode(DisplayMode) | nastavení grafického režimu |
7. Druhý demonstrační příklad: postupné nastavení všech dostupných celoobrazovkových grafických režimů
Metody GraphicsDevice.setFullScreenWindow() a GraphicsDevice.setDisplayMode() jsou využity v dnešním druhém (a současně i posledním :-) demonstračním příkladu. Po spuštění tohoto příkladu se opět získají všechny nainstalované grafické karty a pro každou kartu se následně přečtou dostupné grafické režimy. Následně je každý režim na chvíli (konkrétně na pět sekund, aby se mohl ustálit monitor) nastaven a na obrazovku se vypíšou základní údaje o tomto režimu – rozlišení, bitová hloubka, velikost obrazové paměti (většinou však –1). Povšimněte si, že ve všech režimech je použit stejný objekt typu Frame s textem umístěným uprostřed:
import java.awt.Color; import java.awt.Frame; import java.awt.Font; import java.awt.Label; import java.awt.DisplayMode; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; /** * Ukazka, jakym zpusobem lze nastavit graficke rezimy. */ public class GraphicsModesTest { /** * Vstupni bod do tohoto testu. */ public static void main(String[] args) { GraphicsDevice[] graphicsDevices = getScreenGraphicsDevices(); printInfoAboutEachGraphicsDevice(graphicsDevices); } /** * Ziska pole se vsemi dostupnymi grafickymi zarizenimi. * * @return pole se vsemi dostupnymi grafickymi zarizenimi */ private static GraphicsDevice[] getScreenGraphicsDevices() { GraphicsEnvironment graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice[] graphicsDevices = graphicsEnvironment.getScreenDevices(); return graphicsDevices; } /** * Vypise informaci o vsech grafickych zarizenich predanych v parametru * graphicsDevices. * * @param graphicsDevices * pole se vsemi dostupnymi grafickymi zarizenimi */ private static void printInfoAboutEachGraphicsDevice(GraphicsDevice[] graphicsDevices) { for (int j = 0; j < graphicsDevices.length; j++) { GraphicsDevice graphicsDevice = graphicsDevices[j]; printGraphicsDeviceInfo(graphicsDevice); } } /** * Vypise informaci o grafickem zarizeni predanem v parametru * graphicsDevice. * * @param graphicsDevice * objekt reprezentujici dostupne graficke zarizeni. */ private static void printGraphicsDeviceInfo(GraphicsDevice graphicsDevice) { System.out.println("Device ID: " + graphicsDevice.getIDstring()); System.out.println("Type: " + getDeviceType(graphicsDevice)); System.out.println("Accelerated memory size: " + graphicsDevice.getAvailableAcceleratedMemory()); System.out.println("Display change supported: " + graphicsDevice.isDisplayChangeSupported()); System.out.println("Full screen supported: " + graphicsDevice.isFullScreenSupported()); System.out.println("Transparency/translucency support:"); System.out.println("Graphics modes:"); DisplayMode[] modes = graphicsDevice.getDisplayModes(); tryToSetDisplayModes(graphicsDevice, modes); System.out.println(); } /** * Vrati typ grafickeho zarizeni. * * @param graphicsDevice * objekt reprezentujici dostupne graficke zarizeni. * @return typ zarizeni (textova reprezentace) */ private static String getDeviceType(GraphicsDevice graphicsDevice) { switch (graphicsDevice.getType()) { case GraphicsDevice.TYPE_RASTER_SCREEN: return "raster screen"; case GraphicsDevice.TYPE_PRINTER: return "printer"; case GraphicsDevice.TYPE_IMAGE_BUFFER: return "image buffer"; default: // nemelo by nastat return "???"; } } /** * Pokusi se nastavit vsechny graficke rezimy. * * @param modes pole s grafickymi rezimy pro dane zarizeni. */ private static void tryToSetDisplayModes(GraphicsDevice device, DisplayMode[] modes) { // Frame bude pouzit ve fullscreen rezimu. Frame frame = new Frame(); // Vypis informaci o rezimu bude provaden pres label primo na ramec. Label label = new Label(""); label.setFont(new Font(Font.DIALOG, Font.BOLD, 24)); // zmensit font pro rezim <400x300 pixelu!!! label.setAlignment(Label.CENTER); frame.add(label); // projit vsemi rezimy for (DisplayMode mode : modes) { // zjistit informace o rezimu final int width = mode.getWidth(); final int height = mode. getHeight(); final int bpp = mode.getBitDepth(); final int refreshRate = mode.getRefreshRate(); // nastavit fullscreen rezim device.setFullScreenWindow(frame); device.setDisplayMode(mode); // a vypsat o nem informace System.out.println("Display change supported in FS mode: " + device.isDisplayChangeSupported()); label.setText("Mode: " + width + "x" + height + "@" + bpp + " bpp\t(" + refreshRate + " Hz)"); try { Thread.sleep(5000); } catch (Exception e) { } // zruseni fullscreen rezimu a navrat do "okenniho" rezimu device.setFullScreenWindow(null); } } }
8. Problematika tvorby a vykreslování bitmap podruhé
Jakmile je grafický režim nastaven, lze jednoduše provádět vykreslování do okna či rámce nastaveného metodou GraphicsDevice.setFullScreenWindow(), a to stejným způsobem, jakoby se jednalo o běžné okno. Typicky se však neprovádí žádné vysokoúrovňové operace typu vykreslování tvarů (Shape) s ořezáváním či aplikací afinních transformací. Mnoho 2D her se spokojí s vykreslováním bitmap a zde se dostáváme k problematice zmíněné již minule – aby bylo vykreslování bitmap co nejrychlejší a k tomu ještě prováděné grafickým akcelerátorem, je většinou vyžadováno, aby byl formát těchto bitmap shodný s formátem framebufferu. Toho nelze (obecně) dosáhnout pomocí konstruktoru new BufferedImage(width, height, type), ale je nutné použít jiné metody, konkrétně metody nabízené třídou java.awt.GraphicsConfiguration.
Tyto metody lze rozdělit na dvě části – tvorbu instancí třídy BufferedImage a tvorbu instancí třídy VolatileImage:
Metoda | Popis |
---|---|
GraphicsConfiguration.createCompatibleImage(int width, int height) | základní metoda pro vytvoření bitmapy o zadaných rozměrech |
GraphicsConfiguration.createCompatibleImage(int width, int height, int transparency) | dtto ale s volbou, jak se má reprezentovat průhlednost/průsvitnost |
GraphicsConfiguration.createCompatibleVolatileImage(int width, int height) | základní způsob vytvoření bitmapy typu VolatileImage |
GraphicsConfiguration.createCompatibleVolatileImage(int width, int height, int transparency) | dtto, navíc volba reprezentace průhlednosti/průsvitnosti |
GraphicsConfiguration.createCompatibleVolatileImage(int width, int height, ImageCapabilities caps) | specifikace dalších parametrů (popíšeme příště) |
GraphicsConfiguration.createCompatibleVolatileImage(int width, int height, ImageCapabilities caps, int transparency) | dtto, navíc volba reprezentace průhlednosti/průsvitnosti |
Volba správného typu bitmapy pro vykreslování může velmi významně ovlivnit výkonnost celé aplikace, takže je nutné parametry bitmapy volit takovým způsobem, aby bylo dosaženo požadované funkcionality (například vykreslování spritů), ovšem aby grafický subsystém nemusel provádět zbytečné operace (průhlednost specifikovaná zvlášť pro každý pixel atd. atd.).
9. Repositář se zdrojovými soubory obou demonstračních příkladů
Následují již tradiční odkazy na zdrojové kódy uložené do Mercurial repositáře. V následující tabulce najdete linky na prozatím nejnovější verzi obou dnes popsaných demonstračních příkladů pro zjištění a nastavení všech dostupných grafických režimů:
# | Zdrojový soubor/skript | Umístění souboru v repositáři |
---|---|---|
1 | GraphicsDevicesTest.java | http://icedtea.classpath.org/people/ptisnovs/jvm-tools/file/f6d21d14f927/jvm/gfx/GraphicsDevicesTest.java |
2 | GraphicsModesTest.java | http://icedtea.classpath.org/people/ptisnovs/jvm-tools/file/f6d21d14f927/jvm/gfx/GraphicsModesTest.java |
10. Odkazy na Internetu
- 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