Cara: Menggunakan sumber daya dinamis

API penting

Anda membuat dan menggunakan sumber daya dinamis saat aplikasi perlu mengubah data di sumber daya tersebut. Anda dapat membuat tekstur dan buffer untuk penggunaan dinamis.

Apa yang perlu Anda ketahui

Teknologi

Prasyarat

Kami berasumsi bahwa Anda terbiasa dengan C++. Anda juga memerlukan pengalaman dasar dengan konsep pemrograman grafis.

Petunjuk

Langkah 1: Tentukan penggunaan dinamis

Jika Anda ingin aplikasi dapat membuat perubahan pada sumber daya, Anda harus menentukan sumber daya tersebut sebagai dinamis dan dapat ditulis saat membuatnya.

Untuk menentukan penggunaan dinamis

  1. Tentukan penggunaan sumber daya sebagai dinamis. Misalnya, tentukan nilai D3D11_USAGE_DYNAMIC di anggota PenggunaanD3D11_BUFFER_DESC untuk buffer verteks atau konstanta dan tentukan nilai D3D11_USAGE_DYNAMIC di anggota PenggunaanD3D11_TEXTURE2D_DESC untuk tekstur 2D.
  2. Tentukan sumber daya sebagai bisa-tulis. Misalnya, tentukan nilai D3D11_CPU_ACCESS_WRITE di anggota CPUAccessFlags dari D3D11_BUFFER_DESC atau D3D11_TEXTURE2D_DESC.
  3. Teruskan deskripsi sumber daya ke fungsi pembuatan. Misalnya, teruskan alamat D3D11_BUFFER_DESC ke ID3D11Device::CreateBuffer dan teruskan alamat D3D11_TEXTURE2D_DESC ke ID3D11Device::CreateTexture2D.

Berikut adalah contoh pembuatan buffer vertex dinamis:

    // Create a vertex buffer for a triangle.

    float2 triangleVertices[] =
    {
        float2(-0.5f, -0.5f),
        float2(0.0f, 0.5f),
        float2(0.5f, -0.5f),
    };

    D3D11_BUFFER_DESC vertexBufferDesc = { 0 };
    vertexBufferDesc.ByteWidth = sizeof(float2)* ARRAYSIZE(triangleVertices);
    vertexBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
    vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    vertexBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
    vertexBufferDesc.MiscFlags = 0;
    vertexBufferDesc.StructureByteStride = 0;

    D3D11_SUBRESOURCE_DATA vertexBufferData;
    vertexBufferData.pSysMem = triangleVertices;
    vertexBufferData.SysMemPitch = 0;
    vertexBufferData.SysMemSlicePitch = 0;

    DX::ThrowIfFailed(
        m_d3dDevice->CreateBuffer(
        &vertexBufferDesc,
        &vertexBufferData,
        &vertexBuffer2
        )
        );

Langkah 2: Mengubah sumber daya dinamis

Jika Anda menentukan sumber daya sebagai dinamis dan dapat ditulis saat membuatnya, Anda nantinya dapat membuat perubahan pada sumber daya tersebut.

Untuk mengubah data dalam sumber daya dinamis

  1. Siapkan data baru untuk sumber daya. Deklarasikan variabel jenis D3D11_MAPPED_SUBRESOURCE dan inisialisasi ke nol. Anda akan menggunakan variabel ini untuk mengubah sumber daya.
  2. Nonaktifkan akses unit pemrosesan grafis (GPU) ke data yang ingin Anda ubah dan dapatkan penunjuk ke memori yang berisi data. Untuk mendapatkan pointer ini, teruskan D3D11_MAP_WRITE_DISCARD ke parameter MapType saat Anda memanggil ID3D11DeviceContext::Map. Atur penunjuk ini ke alamat variabel D3D11_MAPPED_SUBRESOURCE dari langkah sebelumnya.
  3. Tulis data baru ke memori.
  4. Panggil ID3D11DeviceContext::Unmap untuk mengaktifkan kembali akses GPU ke data saat Anda selesai menulis data baru.

Berikut adalah contoh mengubah buffer vertex dinamis:

// This might get called as the result of a click event to double the size of the triangle.
void TriangleRenderer::MapDoubleVertices()
{
    D3D11_MAPPED_SUBRESOURCE mappedResource;
    ZeroMemory(&mappedResource, sizeof(D3D11_MAPPED_SUBRESOURCE));
    float2 vertices[] =
    {
        float2(-1.0f, -1.0f),
        float2(0.0f, 1.0f),
        float2(1.0f, -1.0f),
    };
    //  Disable GPU access to the vertex buffer data.
    auto m_d3dContext = m_deviceResources->GetD3DDeviceContext();
    m_d3dContext->Map(vertexBuffer2.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
    //  Update the vertex buffer here.
    memcpy(mappedResource.pData, vertices, sizeof(vertices));
    //  Reenable GPU access to the vertex buffer data.
    m_d3dContext->Unmap(vertexBuffer2.Get(), 0);
}

Keterangan

Menggunakan tekstur dinamis

Kami menyarankan agar Anda hanya membuat satu tekstur dinamis per format dan mungkin per ukuran. Kami tidak menyarankan untuk membuat mipmap, kubus, dan volume dinamis karena overhead tambahan dalam pemetaan setiap tingkat. Untuk mipmap, Anda dapat menentukan D3D11_MAP_WRITE_DISCARD hanya di tingkat atas. Semua tingkat dibuang dengan memetakan hanya tingkat atas. Perilaku ini sama untuk volume dan kubus. Untuk kubus, tingkat atas dan wajah 0 dipetakan.

Menggunakan buffer dinamis

Saat Anda memanggil Peta pada buffer vertex statis saat GPU menggunakan buffer, Anda mendapatkan penalti performa yang signifikan. Dalam situasi ini, Peta harus menunggu sampai GPU selesai membaca puncak atau data indeks dari buffer sebelum Peta dapat kembali ke aplikasi panggilan, yang menyebabkan penundaan yang signifikan. Memanggil Peta lalu merender dari buffer statis beberapa kali per bingkai juga mencegah GPU dari perintah penyajian buffering karena harus menyelesaikan perintah sebelum mengembalikan penunjuk peta. Tanpa perintah buffer, GPU tetap menganggur sampai setelah aplikasi selesai mengisi buffer vertex atau buffer indeks dan mengeluarkan perintah penyajian.

Idealnya vertex atau data indeks tidak akan pernah berubah, tetapi ini tidak selalu mungkin. Ada banyak situasi di mana aplikasi perlu mengubah verteks atau mengindeks data setiap bingkai, bahkan mungkin beberapa kali per bingkai. Untuk situasi ini, kami sarankan Anda membuat puncak atau buffer indeks dengan D3D11_USAGE_DYNAMIC. Bendera penggunaan ini menyebabkan runtime mengoptimalkan operasi peta yang sering. D3D11_USAGE_DYNAMIC hanya berguna ketika buffer sering dipetakan; jika data tetap konstan, tempatkan data tersebut dalam puncak statis atau buffer indeks.

Untuk menerima peningkatan performa saat Anda menggunakan buffer vertex dinamis, aplikasi Anda harus memanggil Peta dengan nilai D3D11_MAP yang sesuai. D3D11_MAP_WRITE_DISCARD menunjukkan bahwa aplikasi tidak perlu menyimpan vertex lama atau data indeks di buffer. Jika GPU masih menggunakan buffer saat Anda memanggil Peta dengan D3D11_MAP_WRITE_DISCARD, runtime mengembalikan pointer ke wilayah memori baru alih-alih data buffer lama. Ini memungkinkan GPU untuk terus menggunakan data lama sementara aplikasi menempatkan data di buffer baru. Tidak diperlukan manajemen memori tambahan di aplikasi; buffer lama digunakan kembali atau dihancurkan secara otomatis ketika GPU selesai dengannya.

Catatan

Saat Anda memetakan buffer dengan D3D11_MAP_WRITE_DISCARD, runtime selalu membuang seluruh buffer. Anda tidak dapat mempertahankan info di area buffer yang tidak dipetakan dengan menentukan offset bukan nol atau bidang ukuran terbatas.

 

Ada kasus di mana jumlah data yang perlu disimpan aplikasi per peta kecil, seperti menambahkan empat simpul untuk merender sprite. D3D11_MAP_WRITE_NO_OVERWRITE menunjukkan bahwa aplikasi tidak akan menimpa data yang sudah digunakan dalam buffer dinamis. Panggilan Peta akan mengembalikan penunjuk ke data lama, yang akan memungkinkan aplikasi untuk menambahkan data baru di wilayah yang tidak digunakan dari puncak atau buffer indeks. Aplikasi tidak boleh memodifikasi simpul atau indeks yang digunakan dalam operasi gambar karena mungkin masih digunakan oleh GPU. Kami menyarankan agar aplikasi kemudian menggunakan D3D11_MAP_WRITE_DISCARD setelah buffer dinamis penuh untuk menerima wilayah memori baru, yang membuang verteks lama atau data indeks setelah GPU selesai.

Mekanisme kueri asinkron berguna untuk menentukan apakah simpul masih digunakan oleh GPU. Terbitkan kueri jenis D3D11_QUERY_EVENT setelah panggilan gambar terakhir yang menggunakan simpul. Simpul tidak lagi digunakan saat ID3D11DeviceContext::GetData mengembalikan S_OK. Saat Anda memetakan buffer dengan nilai D3D11_MAP_WRITE_DISCARD atau tanpa peta, Anda selalu dijamin bahwa simpul disinkronkan dengan benar dengan GPU. Tetapi, ketika Anda memetakan tanpa nilai peta, Anda akan dikenakan penalti performa yang dijelaskan sebelumnya.

Catatan

Runtime Direct3D 11.1, yang tersedia dimulai dengan Windows 8, memungkinkan pemetaan buffer konstan dinamis dan tampilan sumber daya shader (SRV) buffer dinamis dengan D3D11_MAP_WRITE_NO_OVERWRITE. Direct3D 11 dan runtime yang lebih lama membatasi pemetaan pembaruan parsial tanpa timpa ke puncak atau buffer indeks. Untuk menentukan apakah perangkat Direct3D mendukung fitur-fitur ini, panggil ID3D11Device::CheckFeatureSupport dengan D3D11_FEATURE_D3D11_OPTIONS. CheckFeatureSupport mengisi anggota struktur D3D11_FEATURE_DATA_D3D11_OPTIONS dengan fitur perangkat. Anggota yang relevan di sini adalah MapNoOverwriteOnDynamicConstantBuffer dan MapNoOverwriteOnDynamicBufferSRV.

 

Cara Menggunakan Direct3D 11