Pohled pod kapotu JVM – exkluzivní celoobrazovkové grafické režimy

Pavel Tišnovský 3. 12. 2013

Dnešní část seriálu o jazyce Java i o stroji Javy je zaměřena na popis základních vlastností exkluzivních celoobrazovkových grafických režimů, které lze v Javě použít pro tvorbu her a dem. Ukážeme si, jak lze zjistit základní informace o dostupných grafických režimech i jak se provádí zapnutí vybraného režimu.

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

7. Druhý demonstrační příklad: postupné nastavení všech dostupných celoobrazovkových grafických režimů

8. Problematika tvorby a vykreslování bitmap podruhé

9. Repositář se zdrojovými soubory obou demonstračních příkladů

10. Odkazy na Internetu

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.getAvailable­AcceleratedMemory() volná paměť pro alokaci bitmap, mnohdy vrací –1==nelze zjistit
GraphicsDevice.isDisplayChan­geSupported() 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.PERPI­XEL_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_TRAN­SLUCENT). 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.isWindowTran­slucencySupported(WindowTran­slucency.PERPIXEL_TRANSPA­RENT plně průhledné/neprůhledné pixely
GraphicsDevice.isWindowTran­slucencySupported(WindowTran­slucency.TRANSLUCENT průhlednost nastavená pro celou bitmapu/okno
GraphicsDevice.isWindowTran­slucencySupported(WindowTran­slucency.PERPIXEL_TRANSLU­CENT 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é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.Win­dowTranslucency 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.isDisplayChan­geSupported() 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.isDisplayChan­geSupported() 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.setFullScre­enWindow(Window) povolení celoobrazovkového režimu
GraphicsDevice.setFullScre­enWindow(null) vypnutí celoobrazovkového režimu
GraphicsDevice.setDisplay­Mode(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()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:

widgety

Metoda Popis
GraphicsConfiguration.cre­ateCompatibleImage(int width, int height) základní metoda pro vytvoření bitmapy o zadaných rozměrech
GraphicsConfiguration.cre­ateCompatibleImage(int width, int height, int transparency) dtto ale s volbou, jak se má reprezentovat průhlednost/průsvitnost
GraphicsConfiguration.cre­ateCompatibleVolatileImage(int width, int height) základní způsob vytvoření bitmapy typu VolatileImage
GraphicsConfiguration.cre­ateCompatibleVolatileImage(int width, int height, int transparency) dtto, navíc volba reprezentace průhlednosti/průsvitnosti
GraphicsConfiguration.cre­ateCompatibleVolatileImage(int width, int height, ImageCapabilities caps) specifikace dalších parametrů (popíšeme příště)
GraphicsConfiguration.cre­ateCompatibleVolatileImage(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ů:

10. Odkazy na Internetu

  1. Javadoc – třída GraphicsDevice
    http://docs.oracle.com/ja­vase/7/docs/api/java/awt/Grap­hicsDevice.html
  2. Javadoc – třída GraphicsEnvironment
    http://docs.oracle.com/ja­vase/7/docs/api/java/awt/Grap­hicsEnvironment.html
  3. Javadoc – třída GraphicsConfiguration
    http://docs.oracle.com/ja­vase/7/docs/api/java/awt/Grap­hicsConfiguration.html
  4. Javadoc – třída DisplayMode
    http://docs.oracle.com/ja­vase/7/docs/api/java/awt/Dis­playMode.html
  5. Lesson: Full-Screen Exclusive Mode API
    http://docs.oracle.com/ja­vase/tutorial/extra/fullscre­en/
  6. Full-Screen Exclusive Mode
    http://docs.oracle.com/ja­vase/tutorial/extra/fullscre­en/exclusivemode.html
  7. Display Mode
    http://docs.oracle.com/ja­vase/tutorial/extra/fullscre­en/displaymode.html
  8. Using the Full-Screen Exclusive Mode API in Java
    http://www.developer.com/ja­va/other/article.php/3609776/U­sing-the-Full-Screen-Exclusive-Mode-API-in-Java.htm
  9. Java quick guide: JVM Instruction Set (tabulka všech instrukcí JVM)
    http://www.mobilefish.com/tu­torials/java/java_quickgu­ide_jvm_instruction_set.html
  10. The JVM Instruction Set
    http://mpdeboer.home.xs4a­ll.nl/scriptie/node14.html
  11. MultiMedia eXtensions
    http://softpixel.com/~cwrig­ht/programming/simd/mmx.phpi
  12. SSE (Streaming SIMD Extentions)
    http://www.songho.ca/misc/sse/sse­.html
  13. Timothy A. Chagnon: SSE and SSE2
    http://www.cs.drexel.edu/~tc365/mpi-wht/sse.pdf
  14. Intel corporation: Extending the Worldr's Most Popular Processor Architecture
    http://download.intel.com/techno­logy/architecture/new-instructions-paper.pdf
  15. SIMD architectures:
    http://arstechnica.com/ol­d/content/2000/03/simd.ar­s/
  16. GC safe-point (or safepoint) and safe-region
    http://xiao-feng.blogspot.cz/2008/01/gc-safe-point-and-safe-region.html
  17. Safepoints in HotSpot JVM
    http://blog.ragozin.info/2012/10/sa­fepoints-in-hotspot-jvm.html
  18. Java theory and practice: Synchronization optimizations in Mustang
    http://www.ibm.com/develo­perworks/java/library/j-jtp10185/
  19. How to build hsdis
    http://hg.openjdk.java.net/jdk7/hot­spot/hotspot/file/tip/src/sha­re/tools/hsdis/README
  20. Java SE 6 Performance White Paper
    http://www.oracle.com/technet­work/java/6-performance-137236.html
  21. Lukas Stadler's Blog
    http://classparser.blogspot­.cz/2010/03/hsdis-i386dll.html
  22. How to build hsdis-amd64.dll and hsdis-i386.dll on Windows
    http://dropzone.nfshost.com/hsdis.htm
  23. PrintAssembly
    https://wikis.oracle.com/dis­play/HotSpotInternals/Prin­tAssembly
  24. The Java Virtual Machine Specification: 3.14. Synchronization
    http://docs.oracle.com/ja­vase/specs/jvms/se7/html/jvms-3.html#jvms-3.14
  25. The Java Virtual Machine Specification: 8.3.1.4. volatile Fields
    http://docs.oracle.com/ja­vase/specs/jls/se7/html/jls-8.html#jls-8.3.1.4
  26. The Java Virtual Machine Specification: 17.4. Memory Model
    http://docs.oracle.com/ja­vase/specs/jls/se7/html/jls-17.html#jls-17.4
  27. The Java Virtual Machine Specification: 17.7. Non-atomic Treatment of double and long
    http://docs.oracle.com/ja­vase/specs/jls/se7/html/jls-17.html#jls-17.7
  28. Open Source ByteCode Libraries in Java
    http://java-source.net/open-source/bytecode-libraries
  29. ASM Home page
    http://asm.ow2.org/
  30. Seznam nástrojů využívajících projekt ASM
    http://asm.ow2.org/users.html
  31. ObjectWeb ASM (Wikipedia)
    http://en.wikipedia.org/wi­ki/ObjectWeb_ASM
  32. Java Bytecode BCEL vs ASM
    http://james.onegoodcooki­e.com/2005/10/26/java-bytecode-bcel-vs-asm/
  33. BCEL Home page
    http://commons.apache.org/bcel/
  34. Byte Code Engineering Library (před verzí 5.0)
    http://bcel.sourceforge.net/
  35. Byte Code Engineering Library (verze >= 5.0)
    http://commons.apache.org/pro­per/commons-bcel/
  36. BCEL Manual
    http://commons.apache.org/bcel/ma­nual.html
  37. Byte Code Engineering Library (Wikipedia)
    http://en.wikipedia.org/wiki/BCEL
  38. BCEL Tutorial
    http://www.smfsupport.com/sup­port/java/bcel-tutorial!/
  39. Bytecode Engineering
    http://book.chinaunix.net/spe­cial/ebook/Core_Java2_Volu­me2AF/0131118269/ch13lev1sec6­.html
  40. Bytecode Outline plugin for Eclipse (screenshoty + info)
    http://asm.ow2.org/eclipse/index.html
  41. Javassist
    http://www.jboss.org/javassist/
  42. Byteman
    http://www.jboss.org/byteman
  43. Java programming dynamics, Part 7: Bytecode engineering with BCEL
    http://www.ibm.com/develo­perworks/java/library/j-dyn0414/
  44. The JavaTM Virtual Machine Specification, Second Edition
    http://java.sun.com/docs/bo­oks/jvms/second_edition/html/VMSpec­TOC.doc.html
  45. The class File Format
    http://java.sun.com/docs/bo­oks/jvms/second_edition/html/Clas­sFile.doc.html
  46. javap – The Java Class File Disassembler
    http://docs.oracle.com/ja­vase/1.4.2/docs/tooldocs/win­dows/javap.html
  47. javap-java-1.6.0-openjdk(1) – Linux man page
    http://linux.die.net/man/1/javap-java-1.6.0-openjdk
  48. Using javap
    http://www.idevelopment.in­fo/data/Programming/java/mis­cellaneous_java/Using_javap­.html
  49. Examine class files with the javap command
    http://www.techrepublic.com/ar­ticle/examine-class-files-with-the-javap-command/5815354
  50. aspectj (Eclipse)
    http://www.eclipse.org/aspectj/
  51. Aspect-oriented programming (Wikipedia)
    http://en.wikipedia.org/wi­ki/Aspect_oriented_program­ming
  52. AspectJ (Wikipedia)
    http://en.wikipedia.org/wiki/AspectJ
  53. EMMA: a free Java code coverage tool
    http://emma.sourceforge.net/
  54. Cobertura
    http://cobertura.sourceforge.net/
  55. jclasslib bytecode viewer
    http://www.ej-technologies.com/products/jclas­slib/overview.html
Našli jste v článku chybu?
Vitalia.cz: Dostal malý pivovar ze Slovenska do Tesca

Dostal malý pivovar ze Slovenska do Tesca

Podnikatel.cz: EET pro e-shopy? Postavené na hlavu

EET pro e-shopy? Postavené na hlavu

120na80.cz: Co je padesátkrát sladší než cukr?

Co je padesátkrát sladší než cukr?

Podnikatel.cz: Byla finanční manažerka, teď cvičí jógu

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

Vitalia.cz: Jak Ondra o astma přišel

Jak Ondra o astma přišel

DigiZone.cz: O2 Sport zbrojí na derby pražských S

O2 Sport zbrojí na derby pražských S

Vitalia.cz: Jaký je rozdíl mezi brambůrky a chipsy?

Jaký je rozdíl mezi brambůrky a chipsy?

DigiZone.cz: Wimbledon na Nova Sport až do 2019

Wimbledon na Nova Sport až do 2019

Podnikatel.cz: Instalatér, malíř a elektrikář. "Vymřou"?

Instalatér, malíř a elektrikář. "Vymřou"?

DigiZone.cz: Ginx TV: pořad o počítačových hráčích

Ginx TV: pořad o počítačových hráčích

Vitalia.cz: Když všichni seli řepku, on vsadil na dýně

Když všichni seli řepku, on vsadil na dýně

Podnikatel.cz: Znáte už 5 novinek k #EET

Znáte už 5 novinek k #EET

DigiZone.cz: Test: brýle pro virtuální realitu Exos Urban

Test: brýle pro virtuální realitu Exos Urban

Vitalia.cz: Inspekce našla nelegální sklad v SAPĚ. Zase

Inspekce našla nelegální sklad v SAPĚ. Zase

Podnikatel.cz: Chystá se smršť legislativních novinek

Chystá se smršť legislativních novinek

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

Jak se prodává firma za miliardu?

DigiZone.cz: Koncesionářské poplatky pro RTVS

Koncesionářské poplatky pro RTVS

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

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

Vitalia.cz: 5 pravidel proti infekci močových cest

5 pravidel proti infekci močových cest

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

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