27 Şubat 2010 Cumartesi

Nedir Java2D

Bu yazımda Java2D ile ilgili giriş bilgileri vereceğim. Hemen şunu söylemek isterim ki bu yazı kod içermiyor. Bu yazıda daha çok grafik ile ilgili sohbetten ibaret.

Benim ilk programcılık bilgim pek ne yaptığımı bilmesemde basic ile Sinclair ZXSpectrumlar üzerindedir. O zamanlar ekran kartından v.s. den pek bahsetmek mümkün değildi. O zamanlardan DOS zamanlarına atlayıp şöyle bir baktığımızda ise sadece birkaç ekran kartından bahsedilebildiğini görüyoruz. DOS (Disk Operating System) doğrudan donanıma erişimi sağlayan bir işletim sistemiydi. Aslında adından da anlaşılabildiği gibi DOS bir işletim sisteminden ziyade bazı işleri yapmamızı sağlayan rutinlerden oluşan bir sistemdi. İlk gerçek işletim sistemleri olan Windows95, MacOs, Linux, Unix, Solaris, v.s. ise donanıma erişimi doğrudan yapmamızı kısıtlayan sistemlerdir. Doğrudan donanıma erişmek demek komutları işlemci üzerinden donanıma aktarmaktır. Ancak bu durumda her donanımın nasıl çalıştığını programcının bilmesi gerekir. Bu yüzden modern işletim sistemleri hem programcıyı hem donanım üreticisini hemde kullanıcıyı güvenlik açısından (sonuçta direkt donanıma erişilmesi riskli bir iştir.) rahat ettirecek bir katman içerir. Bu katmana donanım soyutlama katmanı yani HAL (Hardware Abstraction Layer) denir. Ancak bu durum işletim sistemini üreten ya da geliştirenlere bir sorumluluk yükler. Bu sorumluluk programcıya donanıma ulaşmak için gereken API'leri sağlamaktır. Aslında HAL'ın ortaya çıkışının bir sebebi ise donanım sayısının her geçen gün artması ve donanım üreticilerin donanımlarına yeni özellik katmaya çalışma çabaları idi. Böylelikle HAL donanım üreticilerine de yeni bir sorumluluk getirdi. Bu sorumluluk doğal olarak donanıma uygun sürücüleri yazma zorunluluğudur. Tabi işletim sistemi bu durumda driver yazmak için donanım üreticilerine de API'ler sağlar. Böylece merkezde işletim sistemi bir tarafda donanım üreticisi diğer tarafda proramcının kendisi vardır. Ancak bazı donanım üreticilerinin görevi driver yazmakdan ziyade driverların da ve donanımların da bu API'lerin implentasyonlarını (uygulamalarını) sağlamak zorundalardır. Mesela OpenGL ve DirectX API'ları Nvidia ve AMD (eski ATI) ekran kartlarında ve bu kartların driverlarında uygulanır. Eğer bu teknik uygulanmasaydı programcı ya da işletim sistemi üreticisi bütün bu donanımların nasıl çalıştığını bilmek ve gereken program ya da sürücü kodlarını yazmak zorunda olacaktı.

Şimdi bu kadar geyikten sonra biraz da çizim meselelerine gelelim. Bilgisayara bağlı çevre birimlerinde çizim yaptırabileceğimiz (çizim yapmak için kullanılan araçlardan bahsetmiyorum) iki ekipman vardır. Bunlar yazıcı ve ekrandır. Windows işletim sistemlerinin bu ekipmanlara yaklaşım tarzı aynıdır. Yani bir program yazarsınız ve çıktı cihazının yazıcı veya ekran olması bir şeyi değiştirmez. Bu konuyu ilerde daha ayrıntılı ele alacağım. Çünkü Javanın yaklaşımı da aynıdır. Ancak Java bu yaklaşımı tüm platformlarda (MacOS, Linux) destekler. Bu cihazlara yapacağımız çizimler eğer 3.boyutu taşımıyorlarsa bu API'ler 2D API'ler dir.

Bazı ortamlar hızlandırılmış çizim ve güvenli çizim olmak üzere iki seçenek sunarlar. Güvenli çizim de çizim işlemi işlemci tarafından yapılır. Çizilmiş nesne bilgisi ekran kartına ekranda görüntülenmesi için gönderilir. Hızlandırılmış çizim ise sadece çizim komutunun ekran kartına gönderilmesinden ibarettir. Ekran kartı gelen bilgilere göre çok hızlı bir biçimde çizimi gerçekleştirir.

Örneğin güvenli çizimde işlemci kullanılarak bir kare çizilip içi doldurulacaksa bir döngü içerisinde kareyi oluşturacak bütün pikseller tek tek boyanır. Ancak işlemci diğer işler içinde kullanılacağı için çizimi tamamlamak uzun sürebilir. Oysa ki hızlandırılmış çizimde istenilen çizim bilgisi sadece ekran kartına gönderilir. Ekran kartı çok hızlı bir biçim de pikselleri doldurur ve işi sadece çizim yapmak olduğu için de herhangi bir kesinti ile performansı düşmez.

Aslında güvenli çizimde kare çizilirken hafızada bir tual (resim) oluşturulur ve çizim buraya yapılır. Sonra bu tual bilgisi hafızadan ekran kartına gönderilir. Her iki durumda da az ya da çok işlemci kullanılır. İşlemci hızlandırılmış modda gerek bilgileri göndermek için gerekse ekran kartı üreticisinin bazı komutları ekran kartının GPU'su (Grafik İşleme Birimi - Graphics Processing Unit) da uygulamak yerine sürücüde uygulaması yüzünden işlemciyi beklenenden fazla kullanabilir. Son cümleyi biraz açayım. GPU ayrı bir donanımdır ve bilgiler kendine ulaştıktan sonra yetenekleri doğrultusunda gerekeni CPU'yu meşgul etmeden yaparlar.

Ancak ekran kartına bilgilerin doğrudan gitme olasılığı yoktur. Hal böyleyken bilgiyi göndermek için tabiki pek çok kod çalıştırılacaktır. Bu kodlar işletim sisteminden ve sürücünün kendinden gelir. Eğer bir işlemi GPU desteklemiyorsa bazen üretici bu işlemi yaptırmak için sürücüyü kullanır. Ancak sürücüyü kullanmak GPU'yu kullanmaktan daha yavaş olsa bile yinede bir çok durumda daha hızlıdır. Çünkü sürücünün işlemci hakimiyeti daha iyidir ve üretici assembly kodları kullanarak daha hızlı işlem yaptırabilir.

Bilgileri doğrudan donanıma gönderemeyeceğimizi söylemiştik ama bunun bir istisnası vardır. Eğer donanım destekliyorsa direkt hafıza erişimi (Direct Memory Access - DMA) denen yöntemle işlemciyi aradan çıkararak hafıza ile donanım arasında bilgi iletimi mümkündür. Ancak şunu unutmamak gerekir işlemci DMA durumunda bile tamamen devre dışı kalmaz. Adı üzerinde CPU Merkezi İşlem Birimi her zaman olayların ortasında her şeyi kontrol eder.

Hızlandırılmış çizim işlemlerinde DirectX veya OpenGL kullanılır. DirectX ve OpenGL donanımın yazılımdan soyutlanmasından sonra yazılımın donanıma erişmesini sağlamak için oluşturulmuş biri Microsoft patentli diğeri Kronos Grup tarafından oluşturulmuş iki API dir. DirectX sadece Microsoft menşeyli ürünlerde kapalı kaynak kodlu API dir. DirectX'in 2D çizim API'ları aslında DirectDraw olarak da geçer. OpenGL ise açık kaynak kodlu olup Microsoft dahil neredeyse kalan bütün platformlarda desteklenen ancak profiller aracılığıyla taşınabilir v.s. gibi ortamlarda farklı özellikleri destekleryen API dir.

Gelelim Java yaklaşımına; Java her iki yaklaşımıda destekler. Aslında Java çalıştığı platformun her türlü avantajını değerlendirmeye çalışır. Ancak Java bazı avantajları kullanması için sizin emirinize ihtiyacı vardır. Bu emirler komut satırından veya JNLP (Java Network Launching Protocol) ile Java sanal makinasına iletilir.

Java çizim görevlerinde arkaplan desteği olarak DirectX veya OpenGL'den yararlanır. Bahsettiğimiz komut satırı değeri Microsoft ortamlarında -Dsun.java2d.d3d=true hem Microsoft hemde diğer ortamlarda -Dsun.java2d.opengl=true dur. Eğer true değerini True olarak girerseniz konsolda bilgi mesajları gözükecektir. Bu değerleri  false olarak değiştirmeniz bu destekleri kapatmanızı garantiler. Ancak bu destekler her zaman doğru çalışmayabilirler. Üstelik bunun sebebi Javadan kaynaklanmıyor olabilir. Bu yüzden güvenli çizim desteği her zaman ve her platformda (istisnalar kaideyi bozmaz) vardır. Güvenli çizim modunu güvenli yapan sonuçta ekran kartının en basit özelliklerini kullanmasıdır.

Java2D ekrana ve yazıcıya birşeyler çizmemize yarayan teknolojinin (API) adıdır. Java3D den farklı olarak çekirdek API'ye dahildir. Yani JRE ve JDK ile gelir ve ayrı kurulum gerektirmez. Yazının devamında ve bundan sonraki yazılarımda ise çizimden kasıtım hem ekrana hemde yazıcıya çizmektir. Ancak çizimlerin yazıcıya gönderimi başka bir yazıda ele alınacaktır.

Java2D'yi kullanırken arada Swing'den de bahsedeceğim. Sonuçta Java2D Swing bileşenlerini oluşturmak için gereken çizim desteğini sağlayan API'ler dir. Java2D ile çizimlerinizi isterseniz AWT paketindeki Canvas'ın alt sınıfı olan Panele isterseniz Canvas'a yapabilirsiniz. Ancak benim önerim daha çok Swing  paketi içindeki JPanel'e yapmanız yönündedir. Çünkü Swing size pek çok avantaj sağlar. Swingin sağladığı bu avantajlar bir sonraki konumuzu teşkil ediyor.