Membuat Sumber Daya Tekstur (Direct3D 10)

Sumber daya tekstur adalah kumpulan data terstruktur. Biasanya, nilai warna disimpan dalam tekstur dan diakses selama penyajian oleh alur pada berbagai tahap untuk input dan output. Membuat tekstur dan menentukan bagaimana mereka akan digunakan adalah bagian penting dari merender adegan yang tampak menarik di Direct3D 10.

Meskipun tekstur biasanya berisi informasi warna, membuat tekstur menggunakan DXGI_FORMAT yang berbeda memungkinkan mereka untuk menyimpan berbagai jenis data. Data ini kemudian dapat dimanfaatkan oleh alur Direct3D 10 dengan cara non-tradisional.

Semua tekstur memiliki batasan berapa banyak memori yang mereka konsumsi, dan berapa banyak texel yang dikandungnya. Batas ini ditentukan oleh konstanta sumber daya.

Membuat Tekstur dari File

Catatan

Pustaka utilitas D3DX tidak digunakan lagi untuk Windows 8 dan tidak didukung untuk aplikasi Windows Store.

 

Saat membuat tekstur di Direct3D 10, Anda juga perlu membuat tampilan. Tampilan adalah objek yang memberi tahu perangkat bagaimana tekstur harus diakses selama penyajian. Cara paling umum untuk mengakses tekstur adalah dengan membacanya menggunakan shader. Tampilan sumber daya shader akan memberi tahu shader cara membaca dari tekstur selama penyajian. Jenis tampilan yang akan digunakan tekstur harus ditentukan saat Anda membuatnya.

Membuat tekstur dan memuat data awalnya dapat dilakukan dengan dua cara berbeda: membuat tekstur dan melihat secara terpisah, atau membuat tekstur dan tampilan secara bersamaan. API menyediakan kedua teknik sehingga Anda dapat memilih mana yang lebih sesuai dengan kebutuhan Anda.

Membuat Tekstur dan Menampilkan Secara Terpisah

Cara termampu untuk membuat tekstur adalah dengan memuatnya dari file gambar. Untuk membuat tekstur, cukup isi satu struktur dan berikan nama tekstur ke D3DX10CreateTextureFromFile.

ID3D10Device *pDevice = NULL;
// Initialize D3D10 device...

D3DX10_IMAGE_LOAD_INFO loadInfo;
ZeroMemory( &loadInfo, sizeof(D3DX10_IMAGE_LOAD_INFO) );
loadInfo.BindFlags = D3D10_BIND_SHADER_RESOURCE;

ID3D10Resource *pTexture = NULL;
D3DX10CreateTextureFromFile( pDevice, L"sample.bmp", &loadInfo, NULL, &pTexture, NULL );

Fungsi D3DX D3DX10CreateTextureFromFile melakukan tiga hal: pertama, membuat objek tekstur Direct3D 10; kedua, membaca file gambar input; ketiga, menyimpan data gambar dalam objek tekstur. Dalam sampel di atas, file BMP dimuat, tetapi fungsi dapat memuat berbagai jenis file.

Bendera ikat menunjukkan tekstur akan dibuat sebagai sumber daya shader yang memungkinkan tahap shader untuk membaca dari tekstur selama penyajian.

Contoh di atas tidak menentukan semua parameter pemuatan. Bahkan, seringkali bermanfaat untuk hanya nol parameter pemuatan karena ini memungkinkan D3DX untuk memilih nilai yang sesuai berdasarkan gambar input. Jika Anda ingin gambar input menentukan semua parameter yang dibuat teksturnya, cukup tentukan NULL untuk parameter loadInfo seperti ini:

D3DX10CreateTextureFromFile( pDevice, L"sample.bmp", NULL, NULL, &pTexture, NULL );

Menentukan NULL untuk informasi pemuatan adalah pintasan sederhana namun kuat.

Sekarang setelah tekstur dibuat, Anda perlu membuat tampilan shader-resource sehingga tekstur dapat diikat sebagai input ke shader. Karena D3DX10CreateTextureFromFile mengembalikan penunjuk ke sumber daya dan bukan penunjuk ke tekstur, Anda harus menentukan jenis sumber daya yang tepat yang dimuat, lalu Anda dapat membuat tampilan sumber daya shader menggunakan CreateShaderResourceView.

D3D10_SHADER_RESOURCE_VIEW_DESC srvDesc;
D3D10_RESOURCE_DIMENSION type;
pTexture->GetType( &type );
switch( type )
{
    case D3D10_RESOURCE_DIMENSION_BUFFER:
    //...
    break;
    case D3D10_RESOURCE_DIMENSION_TEXTURE1D:
    //...
    break;
    case D3D10_RESOURCE_DIMENSION_TEXTURE2D:
    {
        D3D10_TEXTURE2D_DESC desc;
        ID3D10Texture2D *pTexture2D = (ID3D10Texture2D*)pTexture;
        pTexture2D->GetDesc( &desc );
        
        srvDesc.Format = desc.Format;
        srvDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
        srvDesc.Texture2D.MipLevels = desc.MipLevels;
        srvDesc.Texture2D.MostDetailedMip = desc.MipLevels -1;

    }
    break;
    case D3D10_RESOURCE_DIMENSION_TEXTURE3D:
    //...
    break;
    default:
    //...
    break;
}

ID3D10ShaderResourceView *pSRView = NULL;
pDevice->CreateShaderResourceView( pTexture, &srvDesc, &pSRView );

Meskipun sampel di atas membuat tampilan shader-resource 2D, kode untuk membuat jenis tampilan shader-resource lainnya sangat mirip. Tahap shader apa pun sekarang dapat menggunakan tekstur ini sebagai input.

Menggunakan D3DX10CreateTextureFromFile dan CreateShaderResourceView untuk membuat tekstur dan tampilan terkaitnya adalah salah satu cara untuk menyiapkan tekstur agar terikat ke tahap shader. Cara lain untuk melakukannya adalah dengan membuat tekstur dan tampilannya secara bersamaan, yang dibahas di bagian berikutnya.

Membuat Tekstur dan Menampilkan Secara Bersamaan

Direct3D 10 memerlukan tekstur dan tampilan sumber daya shader untuk dibaca dari tekstur selama runtime. Karena pembuatan tekstur dan tampilan sumber daya shader adalah tugas umum, D3DX menyediakan D3DX10CreateShaderResourceViewFromFile untuk melakukannya untuk Anda.

D3DX10_IMAGE_LOAD_INFO loadInfo;
ZeroMemory( &loadInfo, sizeof(D3DX10_IMAGE_LOAD_INFO) );
loadInfo.BindFlags = D3D10_BIND_SHADER_RESOURCE;
loadInfo.Format = DXGI_FORMAT_BC1_UNORM;

ID3D10ShaderResourceView *pSRView = NULL;
D3DX10CreateShaderResourceViewFromFile( pDevice, L"sample.bmp", &loadInfo, NULL, &pSRView, NULL );

Dengan satu panggilan D3DX, tampilan tekstur dan sumber daya shader dibuat. Fungsionalitas parameter loadInfo tidak berubah; Anda dapat menggunakannya untuk menyesuaikan cara tekstur dibuat, atau memperoleh parameter yang diperlukan dari file input dengan menentukan NULL untuk parameter loadInfo .

Objek ID3D10ShaderResourceView yang dikembalikan oleh fungsi D3DX10CreateShaderResourceViewFromFile nantinya dapat digunakan untuk mengambil antarmuka ID3D10Resource asli jika diperlukan. Ini dapat dilakukan dengan memanggil metode GetResource .

D3DX menyediakan satu fungsi untuk membuat tampilan tekstur dan sumber daya shader sebagai keyakinan; Terserah Anda untuk memutuskan metode mana untuk membuat tekstur dan tampilan yang paling sesuai dengan kebutuhan aplikasi Anda.

Sekarang setelah Anda tahu cara membuat tekstur dan tampilan shader-resource-nya, bagian berikutnya akan menunjukkan kepada Anda bagaimana Anda dapat mengambil sampel (baca) dari tekstur tersebut menggunakan shader.

Membuat Tekstur Kosong

Terkadang aplikasi ingin membuat tekstur dan menghitung data yang akan disimpan dalam tekstur, atau menggunakan alur grafis untuk dirender ke tekstur ini dan kemudian menggunakan hasilnya dalam pemrosesan lain. Tekstur ini dapat diperbarui oleh alur grafis atau oleh aplikasi itu sendiri, tergantung pada jenis penggunaan apa yang ditentukan untuk tekstur ketika dibuat.

Penyajian ke tekstur

Kasus paling umum dalam membuat tekstur kosong untuk diisi dengan data selama runtime adalah kasus di mana aplikasi ingin merender ke tekstur dan kemudian menggunakan hasil operasi penyajian dalam pass berikutnya. Tekstur yang dibuat dengan tujuan ini harus menentukan penggunaan default.

Sampel kode berikut membuat tekstur kosong yang dapat dirender oleh alur dan kemudian digunakan sebagai input ke shader.

// Create the render target texture
D3D10_TEXTURE2D_DESC desc;
ZeroMemory( &desc, sizeof(desc) );
desc.Width = 256;
desc.Height = 256;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
desc.SampleDesc.Count = 1;
desc.Usage = D3D10_USAGE_DEFAULT;
desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;

ID3D10Texture2D *pRenderTarget = NULL;
pDevice->CreateTexture2D( &desc, NULL, &pRenderTarget );

Membuat tekstur mengharuskan aplikasi menentukan beberapa informasi tentang properti yang akan dimiliki tekstur. Lebar dan tinggi tekstur dalam texel diatur ke 256. Untuk target render ini, satu tingkat mipmap adalah yang kita butuhkan. Hanya satu target render yang diperlukan sehingga ukuran array diatur ke 1. Setiap texel berisi empat nilai floating point 32-bit, yang dapat digunakan untuk menyimpan informasi yang sangat tepat (lihat DXGI_FORMAT). Satu sampel per piksel adalah semua yang akan diperlukan. Penggunaan diatur ke default karena ini memungkinkan penempatan target render yang paling efisien dalam memori. Akhirnya, fakta bahwa tekstur akan terikat sebagai target render dan sumber daya shader pada titik waktu yang berbeda ditentukan.

Tekstur tidak dapat diikat untuk penyajian ke alur secara langsung; gunakan tampilan target render seperti yang ditunjukkan dalam sampel kode berikut.

D3D10_RENDER_TARGET_VIEW_DESC rtDesc;
rtDesc.Format = desc.Format;
rtDesc.ViewDimension = D3D10_RTV_DIMENSION_TEXTURE2D;
rtDesc.Texture2D.MipSlice = 0;

ID3D10RenderTargetView *pRenderTargetView = NULL;
pDevice->CreateRenderTargetView( pRenderTarget, &rtDesc, &pRenderTargetView );

Format tampilan render-target hanya diatur ke format tekstur asli. Informasi dalam sumber daya harus ditafsirkan sebagai tekstur 2D, dan kami hanya ingin menggunakan tingkat mipmap pertama dari target render.

Demikian pula dengan cara tampilan target render harus dibuat sehingga target render dapat terikat untuk output ke alur, tampilan sumber daya shader harus dibuat sehingga target render dapat terikat ke alur sebagai input. Sampel kode berikut menunjukkan hal ini.

// Create the shader-resource view
D3D10_SHADER_RESOURCE_VIEW_DESC srDesc;
srDesc.Format = desc.Format;
srDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
srDesc.Texture2D.MostDetailedMip = 0;
srDesc.Texture2D.MipLevels = 1;

ID3D10ShaderResourceView *pShaderResView = NULL;
pDevice->CreateShaderResourceView( pRenderTarget, &srDesc, &pShaderResView );

Parameter deskripsi tampilan sumber daya shader sangat mirip dengan deskripsi tampilan target render dan dipilih karena alasan yang sama.

Mengisi Tekstur Secara Manual

Terkadang aplikasi ingin menghitung nilai saat runtime, memasukkannya ke dalam tekstur secara manual lalu meminta alur grafis menggunakan tekstur ini dalam operasi penyajian nanti. Untuk melakukan ini, aplikasi harus membuat tekstur kosong singgah memungkinkan CPU mengakses memori yang mendasar. Ini dilakukan dengan membuat tekstur dinamis dan mendapatkan akses ke memori yang mendasar dengan memanggil metode tertentu. Sampel kode berikut menunjukkan cara melakukannya.

D3D10_TEXTURE2D_DESC desc;
desc.Width = 256;
desc.Height = 256;
desc.MipLevels = desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.Usage = D3D10_USAGE_DYNAMIC;
desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
ID3D10Texture2D *pTexture = NULL;
pd3dDevice->CreateTexture2D( &desc, NULL, &pTexture );

Perhatikan bahwa format diatur ke 32 bit per piksel di mana setiap komponen ditentukan oleh 8 bit. Parameter penggunaan diatur ke dinamis sementara bendera ikat diatur untuk menentukan tekstur akan diakses oleh shader. Deskripsi tekstur lainnya mirip dengan membuat target render.

Pemanggilan Peta memungkinkan aplikasi untuk mengakses memori tekstur yang mendasar. Pointer yang diambil kemudian digunakan untuk mengisi tekstur dengan data. Ini dapat dilihat dalam sampel kode berikut.

D3D10_MAPPED_TEXTURE2D mappedTex;
pTexture->Map( D3D10CalcSubresource(0, 0, 1), D3D10_MAP_WRITE_DISCARD, 0, &mappedTex );

UCHAR* pTexels = (UCHAR*)mappedTex.pData;
for( UINT row = 0; row < desc.Height; row++ )
{
    UINT rowStart = row * mappedTex.RowPitch;
    for( UINT col = 0; col < desc.Width; col++ )
    {
        UINT colStart = col * 4;
        pTexels[rowStart + colStart + 0] = 255; // Red
        pTexels[rowStart + colStart + 1] = 128; // Green
        pTexels[rowStart + colStart + 2] = 64;  // Blue
        pTexels[rowStart + colStart + 3] = 32;  // Alpha
    }
}

pTexture->Unmap( D3D10CalcSubresource(0, 0, 1) );

Beberapa Rendertargets

Hingga delapan tampilan target render dapat terikat ke alur pada satu waktu (dengan OMSetRenderTargets). Untuk setiap piksel (atau setiap sampel jika multisampling diaktifkan), penpaduan dilakukan secara independen untuk setiap tampilan target render. Dua variabel status campuran - BlendEnable dan RenderTargetWriteMask - adalah array delapan, setiap anggota array sesuai dengan tampilan target render. Saat menggunakan beberapa target render, setiap target render harus merupakan jenis sumber daya yang sama (buffer, tekstur 1D, array tekstur 2D, dll.) dan harus memiliki dimensi yang sama (lebar, tinggi, kedalaman untuk tekstur 3D, dan ukuran array untuk array tekstur). Jika target render multisampled, maka semuanya harus memiliki jumlah sampel yang sama per piksel.

Hanya ada satu buffer stensil kedalaman yang aktif, terlepas dari berapa banyak target render yang aktif. Saat menggunakan array tekstur sebagai target render, semua dimensi tampilan harus cocok. Target render tidak perlu memiliki format tekstur yang sama.

Sumber daya (Direct3D 10)