Direct3D'ye Giriş

Direct3D'ye Giriş

DirectX le çalışırken SDK ile gelen Dx dokümanları elimizin altından hiçbir zaman eksik etmememiz gereken en önemli kaynaklardan biri olmalıdır. Nasıl bir buzdolabı, çamaşır makinesinin bir kullanım kılavuzu varsa DirectX inde kullanım kılavuzu SDK ile gelen dokümanlarıdır. Dokümanlar içinde DirectX in barındırdığı bütün sistemler, yapılar , fonksiyonların kullanımları anlatılmaktadır. Yani malzemeler bellidir. Ancak neyin, nerede, ne zaman kullanılacağını da zamanla tecrübe ederek, bol bol araştırarak, okuyarak öğreneceksiniz.

Direct3D ye IDirect3D9 arabiriminden (interface) giriş yapalım. IDirect3D9 arabirimi Direct3D nin temel arabirimlerinden biridir ve bir bakıma Direct3D ye giriş noktası sayılır. Ekran kartının fiziksel bilgilerini, desteklediği özellikleri, görüntü modlarını, desteklenen format bilgilerini alma, Direct3D sürücüsünü oluşturma gibi fonksiyonları içerir.

IDirect3D9 arabiriminin üyeleri

IDirect3D9::CheckDepthStencilMatch: Belirtilen depth-stencil formatının belirtilen render-target formatı ile uyumlu olup olmadığını test etmekte kullanılır.

IDirect3D9::CheckDeviceFormat: Belirtilen yüzey (surface) formatının belirtilen kaynak tipinde doku formatı olarak olarak kullanılabilir mi. Yada depth-stencil buffer veya render target formatı ile kullanılabilir mi. Aslında bunu şöyle açıklayalım. Direct3D de bir çok format tipi vardır. Görüntü (display) formatı, back buffer format, stencil format, texture formatı vs. Bu formatların her biri birbiri ile uyumlu olmayabilir. Yada yukarıda kaynak tipi diye bir ibare kulandık. Kaynak tipi dediğimiz aşağıdaki yapı içerisinde yer alan tanımlardır. Bu format şu kaynak tipi için kullanılabilir mi. Bu format şu formatla uyumlu mu? gibi soruları bu fonksiyonla sorabiliriz.

C/C++ kodu:
typedef enum D3DRESOURCETYPE
{
    D3DRTYPE_SURFACE = 1,
    D3DRTYPE_VOLUME = 2,
    D3DRTYPE_TEXTURE = 3,
    D3DRTYPE_VOLUMETEXTURE = 4,
    D3DRTYPE_CubeTexture = 5,
    D3DRTYPE_VERTEXBUFFER = 6,
    D3DRTYPE_INDEXBUFFER = 7,
    D3DRTYPE_FORCE_DWORD = 0x7fffffff,
} D3DRESOURCETYPE, *LPD3DRESOURCETYPE;

IDirect3D9::CheckDeviceFormatConversion: Bu fonksiyon belirtilen formatın diğer belirttiğimiz bir formata çevrilip çevrilemeyeceğini test etmekte kullanılır.

IDirect3D9::CheckDeviceMultiSampleType: MultiSample (çoklu örnekleme) olayı çizgi, polygonların vs çizimi sırasında oluşan tırtıklanmayı önlemeye yarar. Bu olaya antialising denilmektedir. Bu da daha kaliteli bir görüntü elde etmeye olanak sağlar. Bu fonksiyonla ekran kartımızın bu özelliği destekleyip desteklemediğini, destekliyorsa hangi seviyeye kadar desteklediğini öğrenebiliriz.

Aşağıdaki iki polygondan ilkinde antialising yok ikincisinde ise işlem sonunda meydana gelen düzelmeyi görebilirsiniz. 

IDirect3D9::CheckDeviceType: Belirtilen sürücü tipinin ekran kartı tarafından desteklenip desteklenmediğini test etmekte kullanılır. Direct3D nin desteklediği sürücü tipleri aşağıda verilmiştir.

C/C++ kodu:
typedef enum D3DDEVTYPE
{
    D3DDEVTYPE_HAL = 1,
    D3DDEVTYPE_NULLREF = 4,
    D3DDEVTYPE_REF = 2,
    D3DDEVTYPE_SW = 3,
    D3DDEVTYPE_FORCE_DWORD = 0xffffffff,
} D3DDEVTYPE, *LPD3DDEVTYPE;

IDirect3D9::CreateDevice: Direct3D sürücüsünü oluşturmak için kullanılır.

IDirect3D9::EnumAdapterModes: Belirtilen görüntü formatına ait belirtilen sıradaki mod bilgisini verir.

IDirect3D9::GetAdapterCount: Bilgisayara takılı olan ekran kartı sayısını verir.

IDirect3D9::GetAdapterDisplayMode: Ekran kartının şu an kullandığı görüntü modu bilgisini verir.

IDirect3D9::GetAdapterIdentifier: Belirtilen ekran kartına ait fiziksel bilgileri verir.(Isim, üretici, driver dosyası vs.)

IDirect3D9::GetAdapterModeCount: Ekran kartının belirtilen görüntü formatına ait kaç adet görüntü modu desteklediğinin sayısını verir.

IDirect3D9::GetAdapterMonitor: Bilgisayarımıza birden fazla monitör bağlı ise Direct3D ile çalışan uygulamamızın hangi monitörde çalıştığını öğrenmemizi sağlar.

IDirect3D9::GetDeviceCaps: Ekran kartının desteklediği özellikleri almak için kullanılır.

IDirect3D9::RegisterSoftwareDevice: Kendi yazmış olduğunuz yada başka bir yerden tedarik ettiğiniz software rasterizeri (yazılım tabanlı çizdirici diyelim) Direct3D ile kullanabilmenizi sağlar.

Bu dersimizde DirectX'i kullanarak ekran kartı bilgilerini nasıl elde edeceğimizi öğreneceğiz.
IDirect3D9 arabirimi ile ilgili bu kadar bilgi yeter. Olayı pekiştirmek amacıyla IDirect3D9 arabirimine ait bazı fonksiyonları kullanarak ekran kartımıza ait bazı bilgileri nasıl elde edeceğimizi gösteren ufak bir örnek hazırladım. Örneğimizin MFC ve konsol olmak üzere iki verisyonu bulunmakta. MFC kütüphanesini kullanarak hazırladığım örneğimizde sadece konumuzla ilgili olan kodları ele alacağız.

Örneğimizin görünüşü aşağıdaki gibidir. Ugulama önce sistemde bulunan ekran kartlarını aşağıda gördüğünüz gibi bir combobox içinde listeler. Listelenen ekran kartlarından birini seçtiğimizde de "Desteklenen görüntü modları" kısmında ekran kartının desteklediği çözünürlük, ekran tazeleme ve görüntü formatı bilgilerini listeler. "Ekran kartı bilgileri" kısmında da ekran kartına ait fiziksel bilgilerin bir dökümü listelenir. Bunlar ekran kartının kullandığı sürücü dosyası, ekran kartının adı, sürücü versiyonu, ekran kartının çipsetinin üreticisi, karta ait özel id, ekran kartı üreticisi (board), ekran kartının Microsoft tarafından verilen Windows Hardware Quality Labs (WHQL) onayı var mı yok mu gibi bilgilerdir.

Örneğimizin görüntüsü aşağıdaki gibidir:


Kodlara bir göz atalım.

Aşağıda programımızın başında yapmış olduğumuz tanımlamaları görüyorsunuz.

C/C++ kodu:
#include <d3d9.h> //IDirect3D9 arabiriminin tanımlı olduğu başlık dosyası
#pragma comment(lib,"d3d9.lib")//IDirect3D9 arabiriminin tanımlı olduğu kütüphane 
 
char * FCevir(D3DFORMAT d3dformat);
IDirect3D9 * gD3D9;
D3DADAPTER_IDENTIFIER9  kartidf;//Ekran kartı bilgilerini temsil eden yapı
D3DFORMAT kFormat;//Format bilgilerini temsil eden yapı
D3DDISPLAYMODE kMod;//Görüntü modlarını temsil eden yapı

MFC de ugulamaların açılması sırasında OnInitDialog() fonksiyonu çalışır. Bizde bu fonksiyonun içerisine kendi kodlarımızı yazarak açılışta yapılmasını istediğimiz işlemleri gerçekleştirebiliriz. Aşağıdaki kod parçasında sistemde bulunan ekran kartları formdaki comboboxa ekleme işlemi yapılır.

C/C++ kodu:
BOOL CDXBilgiDlg::OnInitDialog()
{
    CDialog::OnInitDialog();
 
////////////////////////////////////////////////////////////////////
    //Direct3D nesnesini oluştur
    if(NULL==(gD3D9=Direct3DCreate9(D3D_SDK_VERSION))){
        AfxMessageBox("Direct3D yaratılamadı");
    }
     else
    {
        int nKsayi;
        //Bilgisayarda kaç ekran kartı var
        nKsayi=gD3D9->GetAdapterCount();
        for(int k=0;k<=nKsayi-1;k++){
            //Ekran kartı bilgilerini al
            gD3D9->GetAdapterIdentifier(k,NULL,&kartidf);
            //Ekran kartlarının isimlerini comboboxa ekle
            cmb_Kartlar.AddString(kartidf.Description);
        }    
    }
.
.
.
}

Aşağıdaki kod parçasında da comboboxta listelenen ekran kartlarından birini seçtiğimizde ekran kartı ile ilgili bilgileri elde edilmesi ve kontrollere eklenmesi işlemleri yapılır.

C/C++ kodu:
void CDXBilgiDlg::OnCbnSelchangeKartlar()
{
    //Direct3D yaratılamadıysa diğer kodları icra etme
    if(NULL==gD3D9) return;
    //Ekran kartı bilgilerini al
    gD3D9->GetAdapterIdentifier(cmb_Kartlar.GetCurSel(),NULL,&kartidf);
    
    //Elran kartı bilgilerinin olduğu listeyi temizle
    lst_ebilgi.ResetContent();
    
    CString ebilgi;
    //Liste kutusuna eklemek için formatla
    ebilgi.Format("Driver : %s",kartidf.Driver);
    lst_ebilgi.AddString(ebilgi);
    ebilgi.Format("Description : %s",kartidf.Description);
    lst_ebilgi.AddString(ebilgi);    
    ebilgi.Format("DriverVersion : %d",kartidf.DriverVersion);
    lst_ebilgi.AddString(ebilgi);
    ebilgi.Format("DriverVersion.LowPart : %d",kartidf.DriverVersion.LowPart);
    lst_ebilgi.AddString(ebilgi);
    ebilgi.Format("DriverVersion.HighPart : %d",kartidf.DriverVersion.HighPart);
    lst_ebilgi.AddString(ebilgi);
    ebilgi.Format("VendorId : 0x%x",kartidf.VendorId);
    lst_ebilgi.AddString(ebilgi);
    ebilgi.Format("DeviceId : 0x%x",kartidf.DeviceId);
    lst_ebilgi.AddString(ebilgi);
    ebilgi.Format("SubSysId : 0x%x",kartidf.SubSysId);
    lst_ebilgi.AddString(ebilgi);
    ebilgi.Format("Revision : 0x%x",kartidf.Revision);
    lst_ebilgi.AddString(ebilgi);
    ebilgi.Format("DeviceGUID : %x-%x-%x-%x",kartidf.DeviceIdentifier.Data1,
                         kartidf.DeviceIdentifier.Data2,
                         kartidf.DeviceIdentifier.Data3,
                         kartidf.DeviceIdentifier.Data4);
    lst_ebilgi.AddString(ebilgi);    
    
    if(kartidf.WHQLLevel==0){
        lst_ebilgi.AddString("WHQLLevel : WHQL onayı yok");
    }else if(kartidf.WHQLLevel==1){//
        lst_ebilgi.AddString("WHQLLevel : WHQL onayı var");
    }else{
        // DWORD e paketlenmiş tarih verisini aç.
        int  yil =(kartidf.WHQLLevel>>16)&0xFF;
        byte ay  =(kartidf.WHQLLevel>>8)&0x0F; 
        byte gun =(kartidf.WHQLLevel>>0)&0x0F;
        ebilgi.Format("WHQLLevel : WHQL onay tarihi %d-%d-%d",gun,ay,yil);
    }
        
    //*********************************************************
 
    //Direct3D'nin desteklediği görüntü formatları
    D3DFORMAT iFormats[6]=
    {
        D3DFMT_X8R8G8B8,
        D3DFMT_A8R8G8B8,
        D3DFMT_A2R10G10B10,
        D3DFMT_X1R5G5B5,
        D3DFMT_A1R5G5B5,
        D3DFMT_R5G6B5
    };
    
    lst_cozunurluk.ResetContent();//Mod listeleme kutusunu temizle 
    
    CString modlar;
    //Tüm görüntü formatları için dön
    for(int m=0;m<6;m++){
        //Seçili format için desteklenen mod sayısı kadar dön
        for(unsigned int k=0;k<gD3D9->GetAdapterModeCount(cmb_Kartlar.GetCurSel(),iFormats[m]);k++){
            //Sırayla görüntü formatına ait mod bilgilerini al
            gD3D9->EnumAdapterModes(cmb_Kartlar.GetCurSel(),iFormats[m],k,&kMod);
            //Mod bilgisini liste kutusu için formatla
            modlar.Format("%d x %d - %dHz - %s",kMod.Width, //Genişlik
                             kMod.Height, //Yükseklik
                              kMod.RefreshRate, //Tazeleme hızı 
                             FCevir(iFormats[m]) //Görüntü formatı
                             );
            //Modları liste kutusuna ekle
            lst_cozunurluk.AddString(modlar);            
        }    
    }    
}
 
char * FCevir(D3DFORMAT d3dformat){
    switch (d3dformat)
    {
        case D3DFMT_X8R8G8B8: return "D3DFMT_X8R8G8B8";
        case D3DFMT_A8R8G8B8: return "D3DFMT_A8R8G8B8";
        case D3DFMT_A2R10G10B10: return "D3DFMT_A2R10G10B10";
        case D3DFMT_X1R5G5B5: return "D3DFMT_X1R5G5B5";
        case D3DFMT_A1R5G5B5: return "D3DFMT_A1R5G5B5";
        case D3DFMT_R5G6B5: return "D3DFMT_R5G6B5";
    }
    return "";
}
Örneğimizin konsol versiyonu:
 

C/C++ kodu:
#include "stdafx.h"
#include <stdlib.h>
#include <d3d9.h> //IDirect3D9 arabiriminin tanımlı olduğu başlık dosyası
#pragma comment(lib,"d3d9.lib")//IDirect3D9 arabiriminin tanımlı olduğu kütüphane 
 
IDirect3D9 * gD3D9;
D3DADAPTER_IDENTIFIER9  kartidf;//Ekran kartı bilgilerini temsil eden yapı
D3DFORMAT kFormat;//Format bilgilerini temsil eden yapı
D3DDISPLAYMODE kMod;//Görüntü modlarını temsil eden yapı
 
//fonksiyon prototipleri
bool D3DInit();
void KartListesi();
void KartBilgileri(int kart_no);
char * FCevir(D3DFORMAT d3dformat);
 
 
int _tmain(int argc, _TCHAR* argv[])
{
    D3DInit();    
    
    static char secim;
    do{
        system("cls");
        KartListesi();
        fflush(stdin);
        printf("nEkran karti secim: ");
        scanf("%c",&secim);
        if(secim!='x')KartBilgileri(atoi(&secim));                
    }while(secim!='x');
 
    return 0;
}
 
bool D3DInit(){
    //Direct3D nesnesini oluştur
    if(NULL==(gD3D9=Direct3DCreate9(D3D_SDK_VERSION)))
        return false;
    else
        return true;
}
 
void KartListesi(){
    if(gD3D9==NULL) return;
    int nKsayi;
    //Bilgisayarda kaç ekran kartı var
    nKsayi=gD3D9->GetAdapterCount();
    for(int k=0;k<=nKsayi-1;k++){
        //Ekran kartı bilgilerini al
        gD3D9->GetAdapterIdentifier(k,NULL,&kartidf);
        //Ekran kartlarının isimlerini listele
        printf("%d-%s\n",k+1,kartidf.Description);
    }
}
 
void KartBilgileri(int kart_no){
    if(NULL==gD3D9) return;
    kart_no--;
    //Ekran kartı bilgilerini al
    if(D3DERR_INVALIDCALL == gD3D9->GetAdapterIdentifier(kart_no,NULL,&kartidf)){
        printf("nHatali parametren");
        system("pause");
        return;
    };
 
    printf("nEkran karti bilgileri:\n",kartidf.Driver);
    printf("Driver : %s\n",kartidf.Driver);
    printf("Description : %s\n",kartidf.Description);
    printf("DriverVersion : %d",kartidf.DriverVersion);
    printf("DriverVersion.LowPart : %dn",kartidf.DriverVersion.LowPart);
    printf("DriverVersion.HighPart : %dn",kartidf.DriverVersion.HighPart);
    printf("VendorId : 0x%x\n",kartidf.VendorId);
    printf("DeviceId : 0x%x\n",kartidf.DeviceId);
    printf("SubSysId : 0x%x\n",kartidf.SubSysId);
    printf("Revision : 0x%x\n",kartidf.Revision);
    printf("DeviceGUID : %x-%x-%x-%x\n",kartidf.DeviceIdentifier.Data1,
                        kartidf.DeviceIdentifier.Data2,
                        kartidf.DeviceIdentifier.Data3,
                        kartidf.DeviceIdentifier.Data4);
    
    if(kartidf.WHQLLevel==0){
        printf("WHQLLevel : WHQL onayi yok\n");
    }else if(kartidf.WHQLLevel==1){
        printf("WHQLLevel : WHQL onayi var\n");
    }else{
        // DWORD e paketlenmiş tarih verisini aç.
        int  yil =(kartidf.WHQLLevel>>16)&0xFF;
        byte ay  =(kartidf.WHQLLevel>>8)&0x0F; 
        byte gun =(kartidf.WHQLLevel>>0)&0x0F;
        printf("WHQLLevel : WHQL onay tarihi %d-%d-%d\n",gun,ay,yil);
    }
        
    //*********************************************************
    printf("nnDesteklenen goruntu modlari:\n");
 
    //Direct3D'nin desteklediği görüntü formatları
    D3DFORMAT iFormats[6]=
    {
        D3DFMT_X8R8G8B8,
        D3DFMT_A8R8G8B8,
        D3DFMT_A2R10G10B10,
        D3DFMT_X1R5G5B5,
        D3DFMT_A1R5G5B5,
        D3DFMT_R5G6B5
    };
    
    
    for(int m=0;m<6;m++){
        //Seçili format için desteklenen mod sayısı kadar dön
        for(unsigned int k=0;k<gD3D9->GetAdapterModeCount(kart_no,iFormats[m]);k++){
            //Sırayla görüntü formatına ait mod bilgilerini al
            gD3D9->EnumAdapterModes(kart_no,iFormats[m],k,&kMod);
            //Mod bilgisini liste kutusu için formatla
            printf("%d x %d - %dHz - %s\n",kMod.Width, //Genişlik
                        kMod.Height, //Yükseklik
                        kMod.RefreshRate, //Tazeleme hızı                         
                        FCevir(iFormats[m]) //Görüntü formatı
                        );
 
        }    
    }
    system("pause");
}
 
char * FCevir(D3DFORMAT d3dformat){
    switch (d3dformat)
    {
        case D3DFMT_X8R8G8B8: return "D3DFMT_X8R8G8B8";
        case D3DFMT_A8R8G8B8: return "D3DFMT_A8R8G8B8";
        case D3DFMT_A2R10G10B10: return "D3DFMT_A2R10G10B10";
        case D3DFMT_X1R5G5B5: return "D3DFMT_X1R5G5B5";
        case D3DFMT_A1R5G5B5: return "D3DFMT_A1R5G5B5";
        case D3DFMT_R5G6B5: return "D3DFMT_R5G6B5";
    }
    return "";
}

Kaynak kodlar
http://www.mediafire.com/download/p899jbr9mbm8bub/Direct3D_Giris.zip

Bir sonraki dersimizde görüşünceye kadar kendinize iyi bakın.

Bilgin Terzi ( 3ddreams )

Yorumlar

Bu blogdaki popüler yayınlar

SDL Nedir?

Doxygen Kullanımı

OpenGL'de Line (çizgi) Çizdirme