Bagikan melalui


Menggunakan Hambatan Sumber Daya untuk Menyinkronkan Status Sumber Daya di Direct3D 12

Untuk mengurangi penggunaan CPU secara keseluruhan dan mengaktifkan multi-utas driver dan pra-pemrosesan, Direct3D 12 memindahkan tanggung jawab manajemen status per sumber daya dari driver grafis ke aplikasi. Contoh status per sumber daya adalah apakah sumber daya tekstur saat ini sedang diakses sebagai melalui Tampilan Sumber Daya Shader atau sebagai Tampilan Target Render. Di Direct3D 11, driver diperlukan untuk melacak status ini di latar belakang. Ini mahal dari perspektif CPU dan secara signifikan mempersulit segala jenis desain multi-utas. Di Microsoft Direct3D 12, sebagian besar status per sumber daya dikelola oleh aplikasi dengan satu API, ID3D12GraphicsCommandList::ResourceBarrier.

Menggunakan RESOURCEBarrier API untuk mengelola status per sumber daya

ResourceBarrier memberi tahu driver grafis tentang situasi di mana driver mungkin perlu menyinkronkan beberapa akses ke memori tempat sumber daya disimpan. Metode ini dipanggil dengan satu atau beberapa struktur deskripsi pembatas sumber daya yang menunjukkan jenis hambatan sumber daya yang dideklarasikan.

Ada tiga jenis hambatan sumber daya:

  • Hambatan transisi - Hambatan transisi menunjukkan bahwa sekumpulan transisi sub-sumber daya antara penggunaan yang berbeda. Struktur D3D12_RESOURCE_TRANSITION_BARRIER digunakan untuk menentukan subsumber daya yang bertransisi serta status sebelum dan sesudah sub sumber daya.

    Sistem memverifikasi bahwa transisi sub sumber daya dalam daftar perintah konsisten dengan transisi sebelumnya dalam daftar perintah yang sama. Lapisan debug selanjutnya melacak status sub sumber daya untuk menemukan kesalahan lain namun validasi ini konservatif dan tidak lengkap.

    Perhatikan bahwa Anda dapat menggunakan bendera D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES untuk menentukan bahwa semua sub sumber daya dalam sumber daya sedang ditransisikan.

  • Penghalang alias - Penghalang alias menunjukkan transisi antara penggunaan dua sumber daya berbeda yang memiliki pemetaan tumpang tindih ke dalam tumpukan yang sama. Ini berlaku untuk sumber daya yang dipesan dan ditempatkan. Struktur D3D12_RESOURCE_ALIASING_BARRIER digunakan untuk menentukan sumber daya sebelumnya dan sumber daya setelahnya .

    Perhatikan bahwa satu atau kedua sumber daya dapat berupa NULL, yang menunjukkan bahwa sumber daya ubin apa pun dapat menyebabkan alias. Untuk informasi selengkapnya tentang menggunakan sumber daya berjenjang, lihat Sumber daya berjenjang dan Sumber Daya Ubin Volume.

  • Pembatas tampilan akses tidak berurut (UAV) - Hambatan UAV menunjukkan bahwa semua akses UAV, baik baca atau tulis, ke sumber daya tertentu harus diselesaikan antara akses UAV di masa mendatang, baik baca atau tulis. Aplikasi tidak perlu menempatkan penghubung UAV antara dua panggilan gambar atau pengiriman yang hanya dibaca dari UAV. Selain itu, tidak perlu menempatkan hambatan UAV antara dua panggilan gambar atau pengiriman yang menulis ke UAV yang sama jika aplikasi tahu bahwa aman untuk menjalankan akses UAV dalam urutan apa pun. Struktur D3D12_RESOURCE_UAV_BARRIER digunakan untuk menentukan sumber daya UAV tempat pembatas diterapkan. Aplikasi dapat menentukan NULL untuk UAV pembatas, yang menunjukkan bahwa setiap akses UAV dapat memerlukan hambatan.

Ketika ResourceBarrier dipanggil dengan array deskripsi penghalang sumber daya, API berperilaku seolah-olah dipanggil sekali untuk setiap elemen, dalam urutan persediaannya.

Pada waktu tertentu, sub sumber daya berada dalam satu status persis, ditentukan oleh set bendera D3D12_RESOURCE_STATES yang disediakan ke ResourceBarrier. Aplikasi harus memastikan bahwa status sebelum dan sesudah panggilan berturut-turut ke ResourceBarrier setuju.

Tip

Aplikasi harus melakukan batch beberapa transisi ke dalam satu panggilan API sedapat mungkin.

 

Status sumber daya

Untuk daftar lengkap status sumber daya yang dapat ditransisikan sumber daya, lihat topik referensi untuk enumerasi D3D12_RESOURCE_STATES .

Untuk penghalang sumber daya terpisah, lihat juga D3D12_RESOURCE_BARRIER_FLAGS.

Status awal untuk sumber daya

Sumber daya dapat dibuat dengan status awal yang ditentukan pengguna (valid untuk deskripsi sumber daya), dengan pengecualian berikut:

  • Heap pengunggahan harus dimulai dalam status D3D12_RESOURCE_STATE_GENERIC_READ yang merupakan kombinasi OR bitwise:
    • D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER
    • D3D12_RESOURCE_STATE_INDEX_BUFFER
    • D3D12_RESOURCE_STATE_COPY_SOURCE
    • D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE
    • D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
    • D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT
  • Timbunan readback harus dimulai dalam status D3D12_RESOURCE_STATE_COPY_DEST.
  • Buffer swap chain back secara otomatis dimulai dalam status D3D12_RESOURCE_STATE_COMMON.

Sebelum timbunan dapat menjadi target operasi salinan GPU, biasanya tumpukan harus terlebih dahulu ditransisikan ke status D3D12_RESOURCE_STATE_COPY_DEST. Namun, sumber daya yang dibuat pada tumpukan UPLOAD harus dimulai dan tidak dapat berubah dari status GENERIC_READ karena hanya CPU yang akan melakukan penulisan. Sebaliknya, sumber daya berkomitmen yang dibuat dalam timbunan READBACK harus dimulai dan tidak dapat berubah dari status COPY_DEST.

Pembatasan status sumber daya baca/tulis

Bit penggunaan status sumber daya yang digunakan untuk menjelaskan status sumber daya dibagi menjadi status baca-saja dan baca/tulis. Topik referensi untuk D3D12_RESOURCE_STATES menunjukkan tingkat akses baca/tulis untuk setiap bit dalam enumerasi.

Paling banyak, hanya satu bit baca/tulis yang dapat diatur untuk sumber daya apa pun. Jika bit tulis diatur, maka tidak ada bit baca-saja yang dapat diatur untuk sumber daya tersebut. Jika tidak ada bit tulis yang diatur, maka sejumlah bit baca dapat diatur.

Status sumber daya untuk menyajikan kembali buffer

Sebelum buffer belakang disajikan, buffer harus dalam status D3D12_RESOURCE_STATE_COMMON. Perhatikan, status sumber daya D3D12_RESOURCE_STATE_PRESENT adalah sinonim untuk D3D12_RESOURCE_STATE_COMMON, dan keduanya memiliki nilai 0. Jika IDXGISwapChain::P resent (atau IDXGISwapChain1::P resent1) dipanggil pada sumber daya yang saat ini tidak dalam status ini, peringatan lapisan debug dikeluarkan.

Membuang sumber daya

Semua subsumber daya dalam sumber daya harus dalam status RENDER_TARGET, atau status DEPTH_WRITE, untuk merender target/sumber daya stensil kedalaman masing-masing, ketika ID3D12GraphicsCommandList::D iscardResource dipanggil.

Transisi Status Implisit

Sumber daya hanya dapat "dipromosikan" dari D3D12_RESOURCE_STATE_COMMON. Demikian pula, sumber daya hanya akan "membusung" ke D3D12_RESOURCE_STATE_COMMON.

Promosi status umum

Semua sumber daya buffer serta tekstur dengan set bendera D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS secara implisit dipromosikan dari D3D12_RESOURCE_STATE_COMMON ke status yang relevan pada akses GPU pertama, termasuk GENERIC_READ untuk mencakup skenario baca apa pun. Sumber daya apa pun dalam status COMMON dapat diakses seperti melaluinya dalam satu status dengan

1 bendera WRITE, atau 1 bendera READ atau lebih

Sumber daya dapat dipromosikan dari status COMMON berdasarkan tabel berikut:

Bendera status Buffer dan tekstur Simultaneous-Access Tekstur Akses Non-Simultan
VERTEX_AND_CONSTANT_BUFFER Ya Tidak
INDEX_BUFFER Ya Tidak
RENDER_TARGET Ya Tidak
UNORDERED_ACCESS Ya Tidak
DEPTH_WRITE No* Tidak
DEPTH_READ No* Tidak
NON_PIXEL_SHADER_RESOURCE Ya Ya
PIXEL_SHADER_RESOURCE Ya Ya
STREAM_OUT Ya Tidak
INDIRECT_ARGUMENT Ya Tidak
COPY_DEST Ya Ya
COPY_SOURCE Ya Ya
RESOLVE_DEST Ya Tidak
RESOLVE_SOURCE Ya Tidak
PREDIKASI Ya Tidak

 

*Sumber daya stensil kedalaman harus berupa tekstur akses non-simultan dan dengan demikian tidak pernah dapat dipromosikan secara implisit.

Ketika akses ini terjadi, promosi bertindak seperti penghambat sumber daya implisit. Untuk akses berikutnya, hambatan sumber daya akan diperlukan untuk mengubah status sumber daya jika perlu. Perhatikan bahwa promosi dari satu status baca yang dipromosikan ke dalam beberapa status baca valid, tetapi ini tidak terjadi untuk status tulis.
Misalnya, jika sumber daya dalam status umum dipromosikan ke PIXEL_SHADER_RESOURCE dalam panggilan Gambar, sumber daya tersebut masih dapat dipromosikan ke NON_PIXEL_SHADER_RESOURCE | PIXEL_SHADER_RESOURCE dalam panggilan Gambar lain. Namun, jika digunakan dalam operasi tulis, seperti tujuan penyalinan, hambatan transisi status sumber daya dari gabungan status baca yang dipromosikan, di sini NON_PIXEL_SHADER_RESOURCE | PIXEL_SHADER_RESOURCE, untuk COPY_DEST diperlukan.
Demikian pula, jika dipromosikan dari COMMON ke COPY_DEST, hambatan masih diperlukan untuk beralih dari COPY_DEST ke RENDER_TARGET.

Perhatikan bahwa promosi status umum "gratis" karena tidak perlu GPU untuk melakukan penantian sinkronisasi apa pun. Promosi ini mewakili fakta bahwa sumber daya dalam status COMMON seharusnya tidak memerlukan pekerjaan GPU tambahan atau pelacakan driver untuk mendukung akses tertentu.

Pembusuan status ke umum

Sisi balik promosi status umum membusuk kembali ke D3D12_RESOURCE_STATE_COMMON. Sumber daya yang memenuhi persyaratan tertentu dianggap stateless dan secara efektif kembali ke status umum ketika GPU menyelesaikan eksekusi operasi ExecuteCommandLists . Pencairan tidak terjadi di antara daftar perintah yang dijalankan bersama-sama dalam panggilan ExecuteCommandLists yang sama.

Sumber daya berikut akan membusuk ketika operasi ExecuteCommandLists selesai pada GPU:

  • Sumber daya yang diakses pada antrean Salin, atau
  • Buffer sumber daya pada jenis antrean apa pun, atau
  • Sumber daya tekstur pada jenis antrean apa pun yang memiliki bendera D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS diatur, atau
  • Sumber daya apa pun yang secara implisit dipromosikan ke status baca-saja.

Seperti promosi status umum, pembusukan gratis karena tidak ada sinkronisasi tambahan yang diperlukan. Menggabungkan promosi dan pembusukan status umum dapat membantu menghilangkan banyak transisi ResourceBarrier yang tidak perlu. Dalam beberapa kasus, ini dapat memberikan peningkatan performa yang signifikan.

Buffer dan sumber daya Simultaneous-Access akan membusuk ke keadaan umum terlepas dari apakah mereka secara eksplisit beralih menggunakan penghalang sumber daya atau dipromosikan secara implisit.

Implikasi kinerja

Saat merekam transisi ResourceBarrier eksplisit pada sumber daya dalam keadaan umum, sudah benar untuk menggunakan D3D12_RESOURCE_STATE_COMMON atau status yang dapat diproyeksikan sebagai nilai BeforeState dalam struktur D3D12_RESOURCE_TRANSITION_BARRIER. Ini memungkinkan manajemen status tradisional yang mengabaikan pembusukan otomatis buffer dan tekstur akses simultan. Ini mungkin tidak diinginkan, karena menghindari transisi panggilan ResourceBarrier dengan sumber daya yang diketahui berada dalam status umum dapat secara signifikan meningkatkan performa. Penghalang sumber daya bisa mahal. Mereka dirancang untuk memaksa cache flush, perubahan tata letak memori dan sinkronisasi lainnya yang mungkin tidak diperlukan untuk sumber daya yang sudah dalam keadaan umum. Daftar perintah yang menggunakan pembatas sumber daya dari status non-umum ke status non-umum lain pada sumber daya yang saat ini dalam keadaan umum dapat memperkenalkan banyak overhead yang tidak diperlukan.

Selain itu, hindari transisi ResourceBarrier eksplisit ke D3D12_RESOURCE_STATE_COMMON kecuali benar-benar diperlukan (misalnya akses berikutnya ada pada antrean perintah COPY yang memerlukan sumber daya dimulai dalam keadaan umum). Transisi yang berlebihan ke status umum dapat secara dramatis memperlambat performa GPU.

Singkatnya, cobalah untuk mengandalkan promosi status umum dan pembusukan setiap kali semantiknya memungkinkan Anda lolos tanpa mengeluarkan panggilan ResourceBarrier .

Pisahkan Penghalang

Penghubung transisi sumber daya dengan bendera D3D12_RESOURCE_BARRIER_FLAG_BEGIN_ONLY memulai pembatas terpisah dan hambatan transisi dikatakan tertunda. Saat hambatan tertunda sumber daya (sub)tidak dapat dibaca atau ditulis oleh GPU. Satu-satunya hambatan transisi hukum yang dapat diterapkan ke sumber daya (sub)dengan penghubung yang tertunda adalah satu dengan status sebelum dan sesudah yang sama dan bendera D3D12_RESOURCE_BARRIER_FLAG_END_ONLY, yang hambatan menyelesaikan transisi yang tertunda.

Penghalang terpisah memberikan petunjuk ke GPU bahwa sumber daya dalam status A berikutnya akan digunakan dalam status B beberapa waktu kemudian. Ini memberi GPU opsi untuk mengoptimalkan beban kerja transisi, mungkin mengurangi atau menghilangkan kios eksekusi. Mengeluarkan hambatan khusus akhir menjamin bahwa semua pekerjaan transisi GPU selesai sebelum pindah ke perintah berikutnya.

Menggunakan penghalang terpisah dapat membantu meningkatkan performa, terutama dalam skenario multi-mesin atau di mana sumber daya bertransisi baca/tulis jarang di seluruh satu atau beberapa daftar perintah.

Contoh skenario pembatas sumber daya

Cuplikan berikut menunjukkan penggunaan metode ResourceBarrier dalam sampel multi-utas.

Membuat tampilan stensil kedalaman, mentransisikannya ke status yang dapat ditulis.

// Create the depth stencil.
{
    CD3DX12_RESOURCE_DESC shadowTextureDesc(
        D3D12_RESOURCE_DIMENSION_TEXTURE2D,
        0,
        static_cast<UINT>(m_viewport.Width), 
        static_cast<UINT>(m_viewport.Height), 
        1,
        1,
        DXGI_FORMAT_D32_FLOAT,
        1, 
        0,
        D3D12_TEXTURE_LAYOUT_UNKNOWN,
        D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL | D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE);

    D3D12_CLEAR_VALUE clearValue;    // Performance tip: Tell the runtime at resource creation the desired clear value.
    clearValue.Format = DXGI_FORMAT_D32_FLOAT;
    clearValue.DepthStencil.Depth = 1.0f;
    clearValue.DepthStencil.Stencil = 0;

    ThrowIfFailed(m_device->CreateCommittedResource(
        &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
        D3D12_HEAP_FLAG_NONE,
        &shadowTextureDesc,
        D3D12_RESOURCE_STATE_DEPTH_WRITE,
        &clearValue,
        IID_PPV_ARGS(&m_depthStencil)));

    // Create the depth stencil view.
    m_device->CreateDepthStencilView(m_depthStencil.Get(), nullptr, m_dsvHeap->GetCPUDescriptorHandleForHeapStart());
}

Membuat tampilan buffer vertex, pertama-tama mengubahnya dari status umum ke tujuan, lalu dari tujuan ke status yang dapat dibaca secara umum.

// Create the vertex buffer.
{
    ThrowIfFailed(m_device->CreateCommittedResource(
        &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
        D3D12_HEAP_FLAG_NONE,
        &CD3DX12_RESOURCE_DESC::Buffer(SampleAssets::VertexDataSize),
        D3D12_RESOURCE_STATE_COPY_DEST,
        nullptr,
        IID_PPV_ARGS(&m_vertexBuffer)));

    {
        ThrowIfFailed(m_device->CreateCommittedResource(
            &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
            D3D12_HEAP_FLAG_NONE,
            &CD3DX12_RESOURCE_DESC::Buffer(SampleAssets::VertexDataSize),
            D3D12_RESOURCE_STATE_GENERIC_READ,
            nullptr,
            IID_PPV_ARGS(&m_vertexBufferUpload)));

        // Copy data to the upload heap and then schedule a copy 
        // from the upload heap to the vertex buffer.
        D3D12_SUBRESOURCE_DATA vertexData = {};
        vertexData.pData = pAssetData + SampleAssets::VertexDataOffset;
        vertexData.RowPitch = SampleAssets::VertexDataSize;
        vertexData.SlicePitch = vertexData.RowPitch;

        PIXBeginEvent(commandList.Get(), 0, L"Copy vertex buffer data to default resource...");

        UpdateSubresources<1>(commandList.Get(), m_vertexBuffer.Get(), m_vertexBufferUpload.Get(), 0, 0, 1, &vertexData);
        commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_vertexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER));

        PIXEndEvent(commandList.Get());
    }

Membuat tampilan buffer indeks, pertama-tama mengubahnya dari status umum ke tujuan, lalu dari tujuan ke status generik yang dapat dibaca.

// Create the index buffer.
{
    ThrowIfFailed(m_device->CreateCommittedResource(
        &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
        D3D12_HEAP_FLAG_NONE,
        &CD3DX12_RESOURCE_DESC::Buffer(SampleAssets::IndexDataSize),
        D3D12_RESOURCE_STATE_COPY_DEST,
        nullptr,
        IID_PPV_ARGS(&m_indexBuffer)));

    {
        ThrowIfFailed(m_device->CreateCommittedResource(
            &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
            D3D12_HEAP_FLAG_NONE,
            &CD3DX12_RESOURCE_DESC::Buffer(SampleAssets::IndexDataSize),
            D3D12_RESOURCE_STATE_GENERIC_READ,
            nullptr,
            IID_PPV_ARGS(&m_indexBufferUpload)));

        // Copy data to the upload heap and then schedule a copy 
        // from the upload heap to the index buffer.
        D3D12_SUBRESOURCE_DATA indexData = {};
        indexData.pData = pAssetData + SampleAssets::IndexDataOffset;
        indexData.RowPitch = SampleAssets::IndexDataSize;
        indexData.SlicePitch = indexData.RowPitch;

        PIXBeginEvent(commandList.Get(), 0, L"Copy index buffer data to default resource...");

        UpdateSubresources<1>(commandList.Get(), m_indexBuffer.Get(), m_indexBufferUpload.Get(), 0, 0, 1, &indexData);
        commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_indexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_INDEX_BUFFER));

        PIXEndEvent(commandList.Get());
    }

    // Initialize the index buffer view.
    m_indexBufferView.BufferLocation = m_indexBuffer->GetGPUVirtualAddress();
    m_indexBufferView.SizeInBytes = SampleAssets::IndexDataSize;
    m_indexBufferView.Format = SampleAssets::StandardIndexFormat;
}

Membuat tekstur dan tampilan sumber daya shader. Tekstur diubah dari status umum ke tujuan, lalu dari tujuan ke sumber daya shader piksel.

    // Create each texture and SRV descriptor.
    const UINT srvCount = _countof(SampleAssets::Textures);
    PIXBeginEvent(commandList.Get(), 0, L"Copy diffuse and normal texture data to default resources...");
    for (int i = 0; i < srvCount; i++)
    {
        // Describe and create a Texture2D.
        const SampleAssets::TextureResource &tex = SampleAssets::Textures[i];
        CD3DX12_RESOURCE_DESC texDesc(
            D3D12_RESOURCE_DIMENSION_TEXTURE2D,
            0,
            tex.Width, 
            tex.Height, 
            1,
            static_cast<UINT16>(tex.MipLevels),
            tex.Format,
            1, 
            0,
            D3D12_TEXTURE_LAYOUT_UNKNOWN,
            D3D12_RESOURCE_FLAG_NONE);

        ThrowIfFailed(m_device->CreateCommittedResource(
            &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
            D3D12_HEAP_FLAG_NONE,
            &texDesc,
            D3D12_RESOURCE_STATE_COPY_DEST,
            nullptr,
            IID_PPV_ARGS(&m_textures[i])));

        {
            const UINT subresourceCount = texDesc.DepthOrArraySize * texDesc.MipLevels;
            UINT64 uploadBufferSize = GetRequiredIntermediateSize(m_textures[i].Get(), 0, subresourceCount);
            ThrowIfFailed(m_device->CreateCommittedResource(
                &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
                D3D12_HEAP_FLAG_NONE,
                &CD3DX12_RESOURCE_DESC::Buffer(uploadBufferSize),
                D3D12_RESOURCE_STATE_GENERIC_READ,
                nullptr,
                IID_PPV_ARGS(&m_textureUploads[i])));

            // Copy data to the intermediate upload heap and then schedule a copy 
            // from the upload heap to the Texture2D.
            D3D12_SUBRESOURCE_DATA textureData = {};
            textureData.pData = pAssetData + tex.Data->Offset;
            textureData.RowPitch = tex.Data->Pitch;
            textureData.SlicePitch = tex.Data->Size;

            UpdateSubresources(commandList.Get(), m_textures[i].Get(), m_textureUploads[i].Get(), 0, 0, subresourceCount, &textureData);
            commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_textures[i].Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE));
        }

        // Describe and create an SRV.
        D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
        srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
        srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
        srvDesc.Format = tex.Format;
        srvDesc.Texture2D.MipLevels = tex.MipLevels;
        srvDesc.Texture2D.MostDetailedMip = 0;
        srvDesc.Texture2D.ResourceMinLODClamp = 0.0f;
        m_device->CreateShaderResourceView(m_textures[i].Get(), &srvDesc, cbvSrvHandle);

        // Move to the next descriptor slot.
        cbvSrvHandle.Offset(cbvSrvDescriptorSize);
    }

Memulai bingkai; ini tidak hanya menggunakan ResourceBarrier untuk menunjukkan bahwa backbuffer akan digunakan sebagai target render, tetapi juga menginisialisasi sumber daya bingkai (yang memanggil ResourceBarrier pada buffer stensil kedalaman).

// Assemble the CommandListPre command list.
void D3D12Multithreading::BeginFrame()
{
    m_pCurrentFrameResource->Init();

    // Indicate that the back buffer will be used as a render target.
    m_pCurrentFrameResource->m_commandLists[CommandListPre]->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_frameIndex].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));

    // Clear the render target and depth stencil.
    const float clearColor[] = { 0.0f, 0.0f, 0.0f, 1.0f };
    CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart(), m_frameIndex, m_rtvDescriptorSize);
    m_pCurrentFrameResource->m_commandLists[CommandListPre]->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr);
    m_pCurrentFrameResource->m_commandLists[CommandListPre]->ClearDepthStencilView(m_dsvHeap->GetCPUDescriptorHandleForHeapStart(), D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr);

    ThrowIfFailed(m_pCurrentFrameResource->m_commandLists[CommandListPre]->Close());
}

// Assemble the CommandListMid command list.
void D3D12Multithreading::MidFrame()
{
    // Transition our shadow map from the shadow pass to readable in the scene pass.
    m_pCurrentFrameResource->SwapBarriers();

    ThrowIfFailed(m_pCurrentFrameResource->m_commandLists[CommandListMid]->Close());
}

Mengakhiri bingkai, menunjukkan buffer belakang sekarang digunakan untuk menyajikan.

// Assemble the CommandListPost command list.
void D3D12Multithreading::EndFrame()
{
    m_pCurrentFrameResource->Finish();

    // Indicate that the back buffer will now be used to present.
    m_pCurrentFrameResource->m_commandLists[CommandListPost]->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_frameIndex].Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));

    ThrowIfFailed(m_pCurrentFrameResource->m_commandLists[CommandListPost]->Close());
}

Menginisialisasi sumber daya bingkai, yang dipanggil saat memulai bingkai, mentransisikan buffer stensil kedalaman ke yang dapat ditulis.

void FrameResource::Init()
{
    // Reset the command allocators and lists for the main thread.
    for (int i = 0; i < CommandListCount; i++)
    {
        ThrowIfFailed(m_commandAllocators[i]->Reset());
        ThrowIfFailed(m_commandLists[i]->Reset(m_commandAllocators[i].Get(), m_pipelineState.Get()));
    }

    // Clear the depth stencil buffer in preparation for rendering the shadow map.
    m_commandLists[CommandListPre]->ClearDepthStencilView(m_shadowDepthView, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr);

    // Reset the worker command allocators and lists.
    for (int i = 0; i < NumContexts; i++)
    {
        ThrowIfFailed(m_shadowCommandAllocators[i]->Reset());
        ThrowIfFailed(m_shadowCommandLists[i]->Reset(m_shadowCommandAllocators[i].Get(), m_pipelineStateShadowMap.Get()));

        ThrowIfFailed(m_sceneCommandAllocators[i]->Reset());
        ThrowIfFailed(m_sceneCommandLists[i]->Reset(m_sceneCommandAllocators[i].Get(), m_pipelineState.Get()));
    }
}

Hambatan ditukar pertengahan bingkai, transisi peta bayangan dari dapat ditulis ke dapat dibaca.

void FrameResource::SwapBarriers()
{
    // Transition the shadow map from writeable to readable.
    m_commandLists[CommandListMid]->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_shadowTexture.Get(), D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE));
}

Selesai dipanggil ketika bingkai berakhir, transisi peta bayangan ke status umum.

void FrameResource::Finish()
{
    m_commandLists[CommandListPost]->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_shadowTexture.Get(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE));
}

Promosi status umum dan sampel pembusuan

    // Create a buffer resource using D3D12_RESOURCE_STATE_COMMON as the init state
    ID3D12Resource *pResource;
    CreateCommittedVertexBufferInCommonState(1024, &pResource);

    // Copy data to the buffer without the need for a barrier.
    // Promotes pResource state to D3D12_RESOURCE_STATE_COPY_DEST.
    pCommandList->CopyBufferRegion(pResource, 0, pOtherResource, 0, 1024); 

    // To use pResource as a vertex buffer a transition barrier is needed.
    // Note the StateBefore is D3D12_RESOURCE_STATE_COPY_DEST.
    D3D12_RESOURCE_BARRIER BarrierDesc = {};
    BarrierDesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
    BarrierDesc.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
    BarrierDesc.Transition.pResource = pResource;
    BarrierDesc.Transition.Subresource = 0;
    BarrierDesc.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
    BarrierDesc.Transition.StateAfter = D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
    pCommandList->ResourceBarrier( 1, &BarrierDesc );

    // Use pResource as a vertex buffer
    D3D12_VERTEX_BUFFER_VIEW vbView;
    vbView.BufferLocation = pResource->GetGPUVirtualAddress();
    vbView.SizeInBytes = 1024;
    vbView.StrideInBytes = sizeof(MyVertex);

    pCommandList->IASetVertexBuffers(0, 1, &vbView);
    pCommandList->Draw();

    pCommandQueue->ExecuteCommandLists(1, &pCommandList); 
    pCommandList->Reset(pAllocator, pPipelineState);

    // Since the reset command list will be executed in a separate call to 
    // ExecuteCommandLists, the previous state of pResource
    // will have decayed to D3D12_RESOURCE_STATE_COMMON so, again, no barrier is needed
    pCommandList->CopyBufferRegion(pResource, 0, pDifferentResource, 0, 1024);

    FinishRecordingCommandList(pCommandList);
    pCommandQueue->ExecuteCommandLists(1, &pCommandList); 

    WaitForQueue(pCommandQueue);

    // The previous ExecuteCommandLists call has finished so 
    // pResource has decayed to D3D12_RESOURCE_STATE_COMMON

Contoh penghalang terpisah

Contoh berikut menunjukkan cara menggunakan pembatas terpisah untuk mengurangi kios alur. Kode yang mengikuti tidak menggunakan penghalang terpisah:

 D3D12_RESOURCE_BARRIER BarrierDesc = {};
    BarrierDesc.Type = D3D12_RESOURCE_BARRIER_TRANSITION;
    BarrierDesc.Flags = D3D12_RESOURCE_BARRIER_NONE;
    BarrierDesc.Transition.pResource = pResource;
    BarrierDesc.Transition.Subresource = 0;
    BarrierDesc.Transition.StateBefore = D3D12_RESOURCE_STATE_COMMON;
    BarrierDesc.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;

    pCommandList->ResourceBarrier( 1, &BarrierDesc );
    
    Write(pResource); // ... render to pResource
    OtherStuff(); // .. other gpu work

    // Transition pResource to PIXEL_SHADER_RESOURCE
    BarrierDesc.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
    BarrierDesc.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
    
    pCommandList->ResourceBarrier( 1, &BarrierDesc );

    Read(pResource); // ... read from pResource

Kode berikut menggunakan penghalang terpisah:

D3D12_RESOURCE_BARRIER BarrierDesc = {};
    BarrierDesc.Type = D3D12_RESOURCE_BARRIER_TRANSITION;
    BarrierDesc.Flags = D3D12_RESOURCE_BARRIER_NONE;
    BarrierDesc.Transition.pResource = pResource;
    BarrierDesc.Transition.Subresource = 0;
    BarrierDesc.Transition.StateBefore = D3D12_RESOURCE_STATE_COMMON;
    BarrierDesc.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;

    pCommandList->ResourceBarrier( 1, &BarrierDesc );
    
    Write(pResource); // ... render to pResource

    // Done writing to pResource. Start barrier to PIXEL_SHADER_RESOURCE and
    // then do other work
    BarrierDesc.Flags = D3D12_RESOURCE_BARRIER_BEGIN_ONLY;
    BarrierDesc.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
    BarrierDesc.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
    pCommandList->ResourceBarrier( 1, &BarrierDesc );

    OtherStuff(); // .. other gpu work

    // Need to read from pResource so end barrier
    BarrierDesc.Flags = D3D12_RESOURCE_BARRIER_END_ONLY;

    pCommandList->ResourceBarrier( 1, &BarrierDesc );
    Read(pResource); // ... read from pResource

Tutorial video pembelajaran lanjutan DirectX : Hambatan Sumber Daya dan Pelacakan Status

Sinkronisasi multi-mesin

Pengiriman Kerja di Direct3D 12

Tampilan di dalam Penghalang Status Sumber Daya D3D12