Bagikan melalui


D2D menggunakan D3D11on12

Sampel D3D1211on12 menunjukkan cara merender konten D2D melalui konten D3D12 dengan berbagi sumber daya antara perangkat berbasis 11 dan perangkat berbasis 12.

Membuat ID3D11On12Device

Langkah pertama adalah membuat ID3D11On12Device setelah ID3D12Device dibuat, yang melibatkan pembuatan ID3D11Device yang dibungkus di sekitar ID3D12Device melalui API D3D11On12CreateDevice. API ini juga mengambil, di antara parameter lainnya, ID3D12CommandQueue sehingga perangkat 11On12 dapat mengirimkan perintahnya. Setelah ID3D11Device dibuat, Anda dapat meminta antarmuka ID3D11On12Device darinya. Ini adalah objek perangkat utama yang akan digunakan untuk menyiapkan D2D.

Dalam metode LoadPipeline , siapkan perangkat.

 // Create an 11 device wrapped around the 12 device and share
    // 12's command queue.
    ComPtr<ID3D11Device> d3d11Device;
    ThrowIfFailed(D3D11On12CreateDevice(
        m_d3d12Device.Get(),
        d3d11DeviceFlags,
        nullptr,
        0,
        reinterpret_cast<IUnknown**>(m_commandQueue.GetAddressOf()),
        1,
        0,
        &d3d11Device,
        &m_d3d11DeviceContext,
        nullptr
        ));

    // Query the 11On12 device from the 11 device.
    ThrowIfFailed(d3d11Device.As(&m_d3d11On12Device));
Alur panggilan Parameter
ID3D11Device
D3D11On12CreateDevice

 

Membuat pabrik D2D

Sekarang setelah kami memiliki perangkat 11On12, kami menggunakannya untuk membuat pabrik dan perangkat D2D seperti biasanya dilakukan dengan D3D11.

Tambahkan ke metode LoadAssets .

 // Create D2D/DWrite components.
    {
        D2D1_DEVICE_CONTEXT_OPTIONS deviceOptions = D2D1_DEVICE_CONTEXT_OPTIONS_NONE;
        ThrowIfFailed(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory3), &d2dFactoryOptions, &m_d2dFactory));
        ComPtr<IDXGIDevice> dxgiDevice;
        ThrowIfFailed(m_d3d11On12Device.As(&dxgiDevice));
        ThrowIfFailed(m_d2dFactory->CreateDevice(dxgiDevice.Get(), &m_d2dDevice));
        ThrowIfFailed(m_d2dDevice->CreateDeviceContext(deviceOptions, &m_d2dDeviceContext));
        ThrowIfFailed(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &m_dWriteFactory));
    }
Alur panggilan Parameter
D2D1_DEVICE_CONTEXT_OPTIONS
D2D1CreateFactory D2D1_FACTORY_TYPE
IDXGIDevice
ID2D1Factory3::CreateDevice
ID2D1Device::CreateDeviceContext
DWriteCreateFactory DWRITE_FACTORY_TYPE

 

Membuat target render untuk D2D

D3D12 memiliki rantai pertukaran, jadi jika kita ingin merender ke buffer belakang menggunakan perangkat 11On12 (konten D2D), maka kita perlu membuat sumber daya yang dibungkus dari jenis ID3D11Resource dari buffer belakang jenis ID3D12Resource. Ini menautkan ID3D12Resource dengan antarmuka berbasis D3D11 sehingga dapat digunakan dengan perangkat 11On12. Setelah kita memiliki sumber daya yang dibungkus, kita kemudian dapat membuat permukaan target render untuk D2D untuk dirender, juga dalam metode LoadAssets .

// Initialize *hwnd* with the handle of the window displaying the rendered content.
HWND hwnd;

// Query the window's dpi settings, which will be used to create
// D2D's render targets.
float dpi = GetDpiForWindow(hwnd);
D2D1_BITMAP_PROPERTIES1 bitmapProperties = D2D1::BitmapProperties1(
    D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
    D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED),
    dpi,
    dpi);  

// Create frame resources.
{
    CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart());

    // Create a RTV, D2D render target, and a command allocator for each frame.
    for (UINT n = 0; n < FrameCount; n++)
    {
        ThrowIfFailed(m_swapChain->GetBuffer(n, IID_PPV_ARGS(&m_renderTargets[n])));
        m_d3d12Device->CreateRenderTargetView(m_renderTargets[n].Get(), nullptr, rtvHandle);

        // Create a wrapped 11On12 resource of this back buffer. Since we are 
        // rendering all D3D12 content first and then all D2D content, we specify 
        // the In resource state as RENDER_TARGET - because D3D12 will have last 
        // used it in this state - and the Out resource state as PRESENT. When 
        // ReleaseWrappedResources() is called on the 11On12 device, the resource 
        // will be transitioned to the PRESENT state.
        D3D11_RESOURCE_FLAGS d3d11Flags = { D3D11_BIND_RENDER_TARGET };
        ThrowIfFailed(m_d3d11On12Device->CreateWrappedResource(
            m_renderTargets[n].Get(),
            &d3d11Flags,
            D3D12_RESOURCE_STATE_RENDER_TARGET,
            D3D12_RESOURCE_STATE_PRESENT,
            IID_PPV_ARGS(&m_wrappedBackBuffers[n])
            ));

        // Create a render target for D2D to draw directly to this back buffer.
        ComPtr<IDXGISurface> surface;
        ThrowIfFailed(m_wrappedBackBuffers[n].As(&surface));
        ThrowIfFailed(m_d2dDeviceContext->CreateBitmapFromDxgiSurface(
            surface.Get(),
            &bitmapProperties,
            &m_d2dRenderTargets[n]
            ));

        rtvHandle.Offset(1, m_rtvDescriptorSize);

        ThrowIfFailed(m_d3d12Device->CreateCommandAllocator(
            D3D12_COMMAND_LIST_TYPE_DIRECT,
            IID_PPV_ARGS(&m_commandAllocators[n])));
    }
}
Alur panggilan Parameter
GetDpiForWindow Handel jendela
D2D1_BITMAP_PROPERTIES1
BitmapProperties1
[D2D1_BITMAP_OPTIONS] (/windows/desktop/api/d2d1_1/ne-d2d1_1-d2d1_bitmap_options)
[PixelFormat] (/windows/desktop/api/d2d1helper/nf-d2d1helper-pixelformat)
[DXGI_FORMAT] (/windows/desktop/api/dxgiformat/ne-dxgiformat-dxgi_format)
[D2D1_ALPHA_MODE] (/windows/desktop/api/dcommon/ne-dcommon-d2d1_alpha_mode)
CD3DX12_CPU_DESCRIPTOR_HANDLE GetCPUDescriptorHandleForHeapStart
IDXGISwapChain::GetBuffer
CreateRenderTargetView
D3D11_RESOURCE_FLAGS D3D11_BIND_FLAG
CreateWrappedResource D3D12_RESOURCE_STATES
IDXGISurface
ID2D1DeviceContext::CreateBitmapFromDxgiSurface
CreateCommandAllocator D3D12_COMMAND_LIST_TYPE

 

Membuat objek teks D2D dasar

Sekarang kita memiliki ID3D12Device untuk merender konten 3D, ID2D1Device yang dibagikan dengan perangkat 12 kita melalui ID3D11On12Device - yang dapat kita gunakan untuk merender konten 2D - dan keduanya dikonfigurasi untuk dirender ke rantai pertukaran yang sama. Sampel ini hanya menggunakan perangkat D2D untuk merender teks melalui adegan 3D, mirip dengan bagaimana game merender UI mereka. Untuk itu, kita perlu membuat beberapa objek D2D dasar, masih dalam metode LoadAssets .

 // Create D2D/DWrite objects for rendering text.
    {
        ThrowIfFailed(m_d2dDeviceContext->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black), &m_textBrush));
        ThrowIfFailed(m_dWriteFactory->CreateTextFormat(
            L"Verdana",
            NULL,
            DWRITE_FONT_WEIGHT_NORMAL,
            DWRITE_FONT_STYLE_NORMAL,
            DWRITE_FONT_STRETCH_NORMAL,
            50,
            L"en-us",
            &m_textFormat
            ));
        ThrowIfFailed(m_textFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER));
        ThrowIfFailed(m_textFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER));
    }
Alur panggilan Parameter
ID2D1RenderTarget::CreateSolidColorBrush ColorF
IDWriteFactory::CreateTextFormat DWRITE_FONT_WEIGHT
IDWriteTextFormat::SetTextAlignment DWRITE_TEXT_ALIGNMENT
IDWriteTextFormat::SetParagraphAlignment DWRITE_PARAGRAPH_ALIGNMENT

 

Memperbarui perulangan render utama

Sekarang setelah inisialisasi sampel selesai, kita dapat melanjutkan ke perulangan render utama.

// Render the scene.
void D3D1211on12::OnRender()
{
    // Record all the commands we need to render the scene into the command list.
    PopulateCommandList();

    // Execute the command list.
    ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() };
    m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);

    RenderUI();

    // Present the frame.
    ThrowIfFailed(m_swapChain->Present(0, 0));

    MoveToNextFrame();
}
Alur panggilan Parameter
ID3D12CommandList
ExecuteCommandLists
IDXGISwapChain1::P resent1

 

Satu-satunya hal yang baru untuk perulangan render kami adalah panggilan RenderUI , yang akan menggunakan D2D untuk merender UI kami. Perhatikan bahwa kami menjalankan semua daftar perintah D3D12 terlebih dahulu untuk merender adegan 3D kami, dan kemudian kami merender UI kami di atasnya. Sebelum menyelami RenderUI, kita harus melihat perubahan pada PopulateCommandLists. Dalam sampel lain, kami biasanya menempatkan hambatan sumber daya pada daftar perintah sebelum menutupnya untuk transisi buffer belakang dari status target render ke status saat ini. Namun, dalam sampel ini kita menghapus penghalang sumber daya tersebut, karena kita masih perlu merender ke buffer belakang dengan D2D. Perhatikan bahwa ketika kami membuat sumber daya yang dibungkus dari buffer belakang bahwa kami menentukan status target render sebagai status "IN" dan status saat ini sebagai status "OUT".

RenderUI cukup lurus ke depan dalam hal penggunaan D2D. Kami menetapkan target render kami dan merender teks kami. Namun, sebelum menggunakan sumber daya yang dibungkus pada perangkat 11On12, seperti target render buffer belakang kami, kita harus memanggil AcquireWrappedResources API pada perangkat 11On12. Setelah rendering, kami memanggil ReleaseWrappedResources API pada perangkat 11On12. Dengan memanggil ReleaseWrappedResources , kami menimbulkan hambatan sumber daya di belakang layar yang akan mentransisikan sumber daya yang ditentukan ke status "OUT" yang ditentukan pada waktu pembuatan. Dalam kasus kami, ini adalah keadaan saat ini. Akhirnya, untuk mengirimkan semua perintah kami yang dilakukan pada perangkat 11On12 ke ID3D12CommandQueue bersama, kita harus memanggil Flush pada ID3D11DeviceContext.

// Render text over D3D12 using D2D via the 11On12 device.
void D3D1211on12::RenderUI()
{
    D2D1_SIZE_F rtSize = m_d2dRenderTargets[m_frameIndex]->GetSize();
    D2D1_RECT_F textRect = D2D1::RectF(0, 0, rtSize.width, rtSize.height);
    static const WCHAR text[] = L"11On12";

    // Acquire our wrapped render target resource for the current back buffer.
    m_d3d11On12Device->AcquireWrappedResources(m_wrappedBackBuffers[m_frameIndex].GetAddressOf(), 1);

    // Render text directly to the back buffer.
    m_d2dDeviceContext->SetTarget(m_d2dRenderTargets[m_frameIndex].Get());
    m_d2dDeviceContext->BeginDraw();
    m_d2dDeviceContext->SetTransform(D2D1::Matrix3x2F::Identity());
    m_d2dDeviceContext->DrawTextW(
        text,
        _countof(text) - 1,
        m_textFormat.Get(),
        &textRect,
        m_textBrush.Get()
        );
    ThrowIfFailed(m_d2dDeviceContext->EndDraw());

    // Release our wrapped render target resource. Releasing 
    // transitions the back buffer resource to the state specified
    // as the OutState when the wrapped resource was created.
    m_d3d11On12Device->ReleaseWrappedResources(m_wrappedBackBuffers[m_frameIndex].GetAddressOf(), 1);

    // Flush to submit the 11 command list to the shared command queue.
    m_d3d11DeviceContext->Flush();
}
Alur panggilan Parameter
D2D1_SIZE_F
D2D1_RECT_F RectF
AcquireWrappedResources
ID2D1DeviceContext::SetTarget
ID2D1RenderTarget::BeginDraw
ID2D1RenderTarget::SetTransform Matriks3x2F
ID2D1RenderTarget::D rawTextW
ID2D1RenderTarget::EndDraw
ReleaseWrappedResources
ID3D11DeviceContext::Flush

 

Menjalankan sampel

output akhir dari 11 pada 12 sampel

Panduan Kode D3D12

Direct3D 11 pada 12

Direct3D 12 Interop

Referensi 11on12