Gambaran Umum Lapisan

Gambaran umum ini menjelaskan dasar-dasar penggunaan lapisan Direct2D. Ini berisi bagian berikut.

Apa Itu Lapisan?

Lapisan, yang diwakili oleh objek ID2D1Layer , memungkinkan aplikasi untuk memanipulasi sekelompok operasi gambar. Anda menggunakan lapisan dengan "mendorong" ke target render. Operasi gambar berikutnya oleh target render diarahkan ke lapisan . Setelah selesai dengan lapisan, Anda "memunculkan" lapisan dari target render, yang mengkomposisikan konten lapisan kembali ke target render.

Seperti kuas, lapisan adalah sumber daya yang bergantung pada perangkat yang dibuat oleh target render. Lapisan dapat digunakan pada target render apa pun di domain sumber daya yang sama yang berisi target render yang membuatnya. Namun, sumber daya lapisan hanya dapat digunakan oleh satu target render pada satu waktu. Untuk informasi selengkapnya tentang sumber daya, lihat Gambaran Umum Sumber Daya.

Meskipun lapisan menawarkan teknik penyajian yang kuat untuk menghasilkan efek menarik, jumlah lapisan yang berlebihan dalam aplikasi dapat berdampak buruk pada performanya, karena berbagai biaya yang terkait dengan pengelolaan lapisan dan sumber daya lapisan. Misalnya, ada biaya pengisian atau pembersihan lapisan dan kemudian memadukannya kembali, terutama pada perangkat keras kelas atas. Kemudian, ada biaya pengelolaan sumber daya lapisan. Jika Anda sering merealokasi ini, kios yang dihasilkan terhadap GPU akan menjadi masalah yang paling signifikan. Saat Anda merancang aplikasi, cobalah untuk memaksimalkan penggunaan kembali sumber daya lapisan.

Lapisan dalam Windows 8 dan yang lebih baru

Windows 8 memperkenalkan API terkait lapisan baru yang menyederhanakan, meningkatkan performa, dan menambahkan fitur ke lapisan.

ID2D1DeviceContext dan PushLayer

Antarmuka ID2D1DeviceContext berasal dari antarmuka ID2D1RenderTarget dan merupakan kunci untuk menampilkan konten Direct2D di Windows 8, untuk informasi selengkapnya tentang antarmuka ini lihat Perangkat dan Konteks Perangkat. Dengan antarmuka konteks perangkat, Anda dapat melewati panggilan metode CreateLayer dan kemudian meneruskan NULL ke metode ID2D1DeviceContext::P ushLayer . Direct2D secara otomatis mengelola sumber daya lapisan dan dapat berbagi sumber daya antara lapisan dan grafik efek.

D2D1_LAYER_PARAMETERS1 dan D2D1_LAYER_OPTIONS1

Struktur D2D1_LAYER_PARAMETERS1 sama dengan D2D1_LAYER_PARAMETERS, kecuali anggota akhir struktur sekarang menjadi enumerasi D2D1_LAYER_OPTIONS1 .

D2D1_LAYER_OPTIONS1 tidak memiliki opsi ClearType dan memiliki dua opsi berbeda yang dapat Anda gunakan untuk meningkatkan performa:

Mode Campuran

Mulai dari Windows 8, konteks perangkat memiliki mode campuran primitif yang menentukan bagaimana setiap primitif dipadukan dengan permukaan target. Mode ini juga berlaku untuk lapisan saat Anda memanggil metode PushLayer .

Misalnya, jika Anda menggunakan lapisan untuk mengklip primitif dengan transparansi, atur mode D2D1_PRIMITIVE_BLEND_COPY pada konteks perangkat untuk hasil yang tepat. Mode salin membuat konteks perangkat linear menginterpolasi 4 saluran warna, termasuk saluran alfa, dari setiap piksel dengan konten permukaan target sesuai dengan masker geometris lapisan.

Interoperabilitas

Mulai Windows 8, Direct2D mendukung interoperaksi dengan Direct3D dan GDI saat lapisan atau klip didorong. Anda memanggil ID2D1GdiInteropRenderTarget::GetDC saat lapisan didorong untuk beroperasi dengan GDI. Anda memanggil ID2D1DeviceContext::Flush lalu merender ke permukaan yang mendasar untuk beroperasi dengan Direct3D. Anda bertanggung jawab untuk merender di dalam lapisan atau klip dengan Direct3D atau GDI. Jika Anda mencoba merender di luar lapisan atau klip, hasilnya tidak terdefinisi.

Membuat Lapisan

Bekerja dengan lapisan membutuhkan keakraban dengan metode CreateLayer, PushLayer, dan PopLayer , dan struktur D2D1_LAYER_PARAMETERS , yang berisi sekumpulan data parametrik yang menentukan bagaimana lapisan dapat digunakan. Daftar berikut menjelaskan metode dan strukturnya.

  • Panggil metode CreateLayer untuk membuat sumber daya lapisan.

    Catatan

    Mulai dari Windows 8, Anda dapat melewati panggilan metode CreateLayer dan kemudian meneruskan NULL ke metode PushLayer pada antarmuka ID2D1DeviceContext. Ini lebih sederhana dan memungkinkan Direct2D untuk secara otomatis mengelola sumber daya lapisan dan berbagi sumber daya antara lapisan dan grafik efek.

     

  • Setelah target render mulai menggambar (setelah metode BeginDraw-nya dipanggil), Anda dapat menggunakan metode PushLayer . Metode PushLayer menambahkan lapisan yang ditentukan ke target render, sehingga target menerima semua operasi gambar berikutnya hingga PopLayer dipanggil. Metode ini mengambil objek ID2D1Layer yang dikembalikan dengan memanggil CreateLayer dan layerParameters dalam struktur D2D1_LAYER_PARAMETERS . Tabel berikut ini menjelaskan bidang struktur.

    Bidang Deskripsi
    contentBounds Batas konten lapisan. Konten tidak akan dirender di luar batas ini. Parameter ini default ke InfiniteRect. Ketika nilai default digunakan, batas konten secara efektif diambil untuk menjadi batas target render.
    geometricMask (Opsional) Area , didefinisikan oleh ID2D1Geometry, tempat lapisan harus diklip. Atur ke NULL jika lapisan tidak boleh diklip ke geometri.
    maskAntialiasMode Nilai yang menentukan mode antialisis untuk masker geometrik yang ditentukan oleh bidang geometricMask .
    maskTransform Nilai yang menentukan transformasi yang diterapkan ke masker geometris saat menyusun lapisan. Ini relatif terhadap transformasi dunia.
    Opacity Nilai opasitas lapisan. Tingkat keburaman setiap sumber daya dalam lapisan dikalikan dengan nilai ini saat menyusun ke target.
    opacityBrush (Opsional) Kuas yang digunakan untuk memodifikasi tingkat keburaman lapisan. Kuas dipetakan ke lapisan, dan saluran alfa dari setiap piksel kuas yang dipetakan dikalikan dengan piksel lapisan yang sesuai. Atur ke NULL jika lapisan tidak boleh memiliki masker opasitas.
    layerOptions Nilai yang menentukan apakah lapisan berniat untuk merender teks dengan antialias ClearType. Parameter ini default ke nonaktif. Mengaktifkannya memungkinkan ClearType bekerja dengan benar, tetapi menghasilkan kecepatan penyajian yang sedikit lebih lambat.

     

    Catatan

    Mulai dari Windows 8, Anda tidak dapat merender dengan ClearType dalam lapisan, sehingga parameter layerOptions harus selalu diatur ke D2D1_LAYER_OPTIONS_NONE

     

    Untuk kenyamanan, Direct2D menyediakan metode D2D1::LayerParameters untuk membantu Anda membuat struktur D2D1_LAYER_PARAMETERS .

  • Untuk menyusun konten lapisan ke target render, panggil metode PopLayer . Anda harus memanggil metode PopLayer sebelum memanggil metode EndDraw .

Contoh berikut menunjukkan cara menggunakan CreateLayer, PushLayer, dan PopLayer. Semua bidang dalam struktur D2D1_LAYER_PARAMETERS diatur ke defaultnya, kecuali opacityBrush, yang diatur ke ID2D1RadialGradientBrush.

// Create a layer.
ID2D1Layer *pLayer = NULL;
hr = pRT->CreateLayer(NULL, &pLayer);

if (SUCCEEDED(hr))
{
    pRT->SetTransform(D2D1::Matrix3x2F::Translation(300, 250));

    // Push the layer with the content bounds.
    pRT->PushLayer(
        D2D1::LayerParameters(
            D2D1::InfiniteRect(),
            NULL,
            D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
            D2D1::IdentityMatrix(),
            1.0,
            m_pRadialGradientBrush,
            D2D1_LAYER_OPTIONS_NONE),
        pLayer
        );

    pRT->DrawBitmap(m_pBambooBitmap, D2D1::RectF(0, 0, 190, 127));

    pRT->FillRectangle(
        D2D1::RectF(25.f, 25.f, 50.f, 50.f), 
        m_pSolidColorBrush
        );
    pRT->FillRectangle(
        D2D1::RectF(50.f, 50.f, 75.f, 75.f),
        m_pSolidColorBrush
        ); 
    pRT->FillRectangle(
        D2D1::RectF(75.f, 75.f, 100.f, 100.f),
        m_pSolidColorBrush
        );    
 
    pRT->PopLayer();
}
SafeRelease(&pLayer);

Kode telah dihilangkan dari contoh ini.

Perhatikan bahwa saat Anda memanggil PushLayer dan PopLayer, pastikan bahwa setiap PushLayer memiliki panggilan PopLayer yang cocok. Jika ada lebih banyak panggilan PopLayer daripada panggilan PushLayer , target render ditempatkan ke dalam status kesalahan. Jika Flush dipanggil sebelum semua lapisan yang luar biasa muncul, target render ditempatkan ke dalam status kesalahan dan mengembalikan kesalahan. Untuk menghapus status kesalahan, gunakan EndDraw.

Batas Isi

contentBounds menetapkan batas apa yang akan digambar ke lapisan. Hanya hal-hal dalam batas konten yang terdiri kembali ke target render.

Contoh berikut menunjukkan cara menentukan contentBounds sehingga gambar asli dipotong ke batas konten dengan sudut kiri atas di (10, 108) dan sudut kanan bawah di (121, 177). Ilustrasi berikut menunjukkan gambar asli dan hasil kliping gambar ke batas konten.

ilustrasi isi terikat pada gambar asli dan gambar terpotong yang dihasilkan

HRESULT DemoApp::RenderWithLayerWithContentBounds(ID2D1RenderTarget *pRT)
{
    
    HRESULT hr = S_OK;

    // Create a layer.
    ID2D1Layer *pLayer = NULL;
    hr = pRT->CreateLayer(NULL, &pLayer);

    if (SUCCEEDED(hr))
    {
        pRT->SetTransform(D2D1::Matrix3x2F::Translation(300, 0));

        // Push the layer with the content bounds.
        pRT->PushLayer(
            D2D1::LayerParameters(D2D1::RectF(10, 108, 121, 177)),
            pLayer
            );

        pRT->DrawBitmap(m_pWaterBitmap, D2D1::RectF(0, 0, 128, 192));
        pRT->PopLayer();
    }

    SafeRelease(&pLayer);

    return hr;
    
}

Kode telah dihilangkan dari contoh ini.

Catatan

Gambar yang diklip lebih lanjut terpengaruh jika Anda menentukan geometricMask. Lihat bagian Masker Geometris untuk informasi selengkapnya.

 

Masker Geometris

Masker geometris adalah klip atau potongan, yang ditentukan oleh objek ID2D1Geometry , yang menutupi lapisan saat digambar oleh target render. Anda dapat menggunakan bidang geometricMask dari struktur D2D1_LAYER_PARAMETERS untuk menutupi hasilnya ke geometri. Misalnya, jika Anda ingin menampilkan gambar yang diselubungi oleh huruf blok "A", Anda dapat terlebih dahulu membuat geometri yang mewakili huruf blok "A" dan menggunakan geometri tersebut sebagai masker geometris untuk lapisan. Kemudian, setelah mendorong lapisan, Anda dapat menggambar gambar. Memunculkan lapisan menghasilkan gambar yang diklip ke bentuk huruf blok "A".

Contoh berikut menunjukkan cara membuat ID2D1PathGeometry yang berisi bentuk gunung lalu meneruskan geometri jalur ke PushLayer. Kemudian menggambar bitmap dan kotak. Jika hanya ada bitmap di lapisan yang akan dirender, gunakan FillGeometry dengan kuas bitmap yang dijepit untuk efisiensi. Ilustrasi berikut menunjukkan output dari contoh.

ilustrasi gambar daun dan gambar yang dihasilkan setelah topeng geometris gunung diterapkan

Contoh pertama mendefinisikan geometri yang akan digunakan sebagai masker.

hr = m_pD2DFactory->CreatePathGeometry(&m_pPathGeometry);
    
if(SUCCEEDED(hr))
{
    ID2D1GeometrySink *pSink = NULL;
    // Write to the path geometry using the geometry sink.
    hr = m_pPathGeometry->Open(&pSink);

    if (SUCCEEDED(hr))
    {
        pSink->SetFillMode(D2D1_FILL_MODE_WINDING);
        pSink->BeginFigure(
            D2D1::Point2F(0, 90),
            D2D1_FIGURE_BEGIN_FILLED
            );

        D2D1_POINT_2F points[7] = {
           D2D1::Point2F(35, 30),
           D2D1::Point2F(50, 50),
           D2D1::Point2F(70, 45),
           D2D1::Point2F(105, 90),
           D2D1::Point2F(130, 90),
           D2D1::Point2F(150, 60),
           D2D1::Point2F(170, 90)
           };

        pSink->AddLines(points, 7);
        pSink->EndFigure(D2D1_FIGURE_END_CLOSED);
        hr = pSink->Close();
    }
    SafeRelease(&pSink);
       }

Contoh berikutnya menggunakan geometri sebagai masker untuk lapisan.

HRESULT DemoApp::RenderWithLayerWithGeometricMask(ID2D1RenderTarget *pRT)
{
    
    HRESULT hr;

    // Create a layer.
    ID2D1Layer *pLayer = NULL;
    hr = pRT->CreateLayer(NULL, &pLayer);

    if (SUCCEEDED(hr))
    {
        pRT->SetTransform(D2D1::Matrix3x2F::Translation(300, 450));

        pRT->PushLayer(
            D2D1::LayerParameters(D2D1::InfiniteRect(), m_pPathGeometry),
            pLayer
            );

        pRT->DrawBitmap(m_pLeafBitmap, D2D1::RectF(0, 0, 198, 132));

        pRT->FillRectangle(
            D2D1::RectF(50.f, 50.f, 75.f, 75.f), 
            m_pSolidColorBrush
            ); 
        pRT->FillRectangle(
            D2D1::RectF(75.f, 75.f, 100.f, 100.f),
            m_pSolidColorBrush
            );        

        pRT->PopLayer();
    }

    SafeRelease(&pLayer);

    return hr;
    
}

Kode telah dihilangkan dari contoh ini.

Catatan

Secara umum, jika Anda menentukan geometricMask, Anda dapat menggunakan nilai default, InfiniteRect, untuk contentBounds.

Jika contentBounds adalah NULL, dan geometricMask bukan NULL, maka batas konten secara efektif adalah batas masker geometris setelah transformasi mask diterapkan.

Jika contentBounds non-NULL, dan geometricMask non-NULL, maka masker geometris yang diubah secara efektif dipotong terhadap batas konten dan batas konten diasumsikan tidak terbatas.

 

Masker Opasitas

Masker opasitas adalah masker, yang dijelaskan oleh kuas atau bitmap, yang diterapkan ke objek lain untuk membuat objek itu sebagian atau benar-benar transparan. Ini memungkinkan penggunaan saluran alfa kuas untuk digunakan sebagai masker konten. Misalnya, Anda dapat menentukan kuas gradien radial yang bervariasi dari buram hingga transparan untuk membuat efek sketsa.

Contoh berikut menggunakan ID2D1RadialGradientBrush (m_pRadialGradientBrush) sebagai masker opasitas. Kemudian menggambar bitmap dan kotak. Jika hanya ada bitmap di lapisan yang akan dirender, gunakan FillGeometry dengan kuas bitmap yang dijepit untuk efisiensi. Ilustrasi berikut menunjukkan output dari contoh ini.

ilustrasi gambar pohon dan gambar yang dihasilkan setelah masker opasitas diterapkan

HRESULT DemoApp::RenderWithLayerWithOpacityMask(ID2D1RenderTarget *pRT)
{   

    HRESULT hr = S_OK;

    // Create a layer.
    ID2D1Layer *pLayer = NULL;
    hr = pRT->CreateLayer(NULL, &pLayer);

    if (SUCCEEDED(hr))
    {
        pRT->SetTransform(D2D1::Matrix3x2F::Translation(300, 250));

        // Push the layer with the content bounds.
        pRT->PushLayer(
            D2D1::LayerParameters(
                D2D1::InfiniteRect(),
                NULL,
                D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
                D2D1::IdentityMatrix(),
                1.0,
                m_pRadialGradientBrush,
                D2D1_LAYER_OPTIONS_NONE),
            pLayer
            );

        pRT->DrawBitmap(m_pBambooBitmap, D2D1::RectF(0, 0, 190, 127));

        pRT->FillRectangle(
            D2D1::RectF(25.f, 25.f, 50.f, 50.f), 
            m_pSolidColorBrush
            );
        pRT->FillRectangle(
            D2D1::RectF(50.f, 50.f, 75.f, 75.f),
            m_pSolidColorBrush
            ); 
        pRT->FillRectangle(
            D2D1::RectF(75.f, 75.f, 100.f, 100.f),
            m_pSolidColorBrush
            );    
 
        pRT->PopLayer();
    }
    SafeRelease(&pLayer);
   
    return hr;
    
}

Kode telah dihilangkan dari contoh ini.

Catatan

Contoh ini menggunakan lapisan untuk menerapkan masker opasitas ke satu objek untuk menjaga contoh sesingkat mungkin. Saat menerapkan masker opasitas ke satu objek, lebih efisien untuk menggunakan metode FillOpacityMask atau FillGeometry , bukan lapisan.

 

Untuk petunjuk tentang cara menerapkan masker opasitas tanpa menggunakan lapisan, lihat Gambaran Umum Masker Opacity.

Alternatif untuk Layers

Seperti disebutkan sebelumnya, jumlah lapisan yang berlebihan dapat berdampak buruk pada performa aplikasi Anda. Untuk meningkatkan performa, hindari menggunakan lapisan jika memungkinkan; sebaliknya menggunakan alternatif mereka. Contoh kode berikut menunjukkan cara menggunakan PushAxisAlignedClip dan PopAxisAlignedClip untuk mengklip wilayah, sebagai alternatif untuk menggunakan lapisan dengan batas konten.

pRT->PushAxisAlignedClip(
    D2D1::RectF(20, 20, 100, 100),
    D2D1_ANTIALIAS_MODE_PER_PRIMITIVE
    );

pRT->FillRectangle(D2D1::RectF(0, 0, 200, 133), m_pOriginalBitmapBrush);
pRT->PopAxisAlignedClip();

Demikian pula, gunakan FillGeometry dengan kuas bitmap yang dijepit sebagai alternatif untuk menggunakan lapisan dengan masker opasitas ketika hanya ada satu konten di lapisan yang akan dirender, seperti yang ditunjukkan dalam contoh berikut.

        m_pRenderTarget->FillGeometry(
            m_pRectGeo, 
            m_pLinearFadeFlowersBitmapBrush, 
            m_pLinearGradientBrush
            );

Sebagai alternatif untuk menggunakan lapisan dengan masker geometris, pertimbangkan untuk menggunakan masker bitmap untuk mengklip wilayah, seperti yang ditunjukkan dalam contoh berikut.

// D2D1_ANTIALIAS_MODE_ALIASED must be set for FillOpacityMask
// to function properly.
m_pRenderTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);

m_pRenderTarget->FillOpacityMask(
    m_pBitmapMask,
    m_pOriginalBitmapBrush,
    D2D1_OPACITY_MASK_CONTENT_GRAPHICS,
    &rcBrushRect,
    NULL
    );

m_pRenderTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);

Terakhir, jika Anda ingin menerapkan opasitas ke satu primitif, Anda harus mengalikan opasitas ke dalam warna kuas dan kemudian merender primitif. Anda tidak memerlukan lapisan atau bitmap masker opasitas.

float opacity = 0.9f;

ID2D1SolidColorBrush *pBrush = NULL;
hr = pCompatibleRenderTarget->CreateSolidColorBrush(
    D2D1::ColorF(D2D1::ColorF(0.93f, 0.94f, 0.96f, 1.0f * opacity)),
    &pBrush
    );

m_pRenderTarget->FillRectangle(
    D2D1::RectF(50.0f, 50.0f, 75.0f, 75.0f), 
    pBrush
    ); 

Mengklip bentuk arbitrer

Gambar di sini menunjukkan hasil penerapan klip ke gambar.

gambar yang memperlihatkan contoh gambar sebelum dan sesudah klip.

Anda bisa mendapatkan hasil ini dengan menggunakan lapisan dengan masker geometri atau metode FillGeometry dengan kuas opasitas.

Berikut adalah contoh yang menggunakan lapisan:

// Call PushLayer() and pass in the clipping geometry.
m_d2dContext->PushLayer(
    D2D1::LayerParameters(
        boundsRect,
        geometricMask));

Berikut adalah contoh yang menggunakan metode FillGeometry :

// Create an opacity bitmap and render content.
m_d2dContext->CreateBitmap(size, nullptr, 0,
    D2D1::BitmapProperties(
        D2D1_BITMAP_OPTIONS_TARGET,
        D2D1::PixelFormat(
            DXGI_FORMAT_A8_UNORM,
            D2D1_ALPHA_MODE_PREMULTIPLIED),
        dpiX, dpiY),
    &opacityBitmap);

m_d2dContext->SetTarget(opacityBitmap.Get());
m_d2dContext->BeginDraw();
…
m_d2dContext->EndDraw();

// Create an opacity brush from the opacity bitmap.
m_d2dContext->CreateBitmapBrush(opacityBitmap.Get(),
    D2D1::BitmapBrushProperties(),
    D2D1::BrushProperties(),
    &bitmapBrush);

// Call the FillGeometry method and pass in the clip geometry and the opacity brush
m_d2dContext->FillGeometry( 
    clipGeometry.Get(),
    brush.Get(),
    opacityBrush.Get()); 

Dalam contoh kode ini, saat Anda memanggil metode PushLayer, Anda tidak meneruskan lapisan yang dibuat aplikasi. Direct2D membuat lapisan untuk Anda. Direct2D dapat mengelola alokasi dan penghancuran sumber daya ini tanpa keterlibatan dari aplikasi. Ini memungkinkan Direct2D untuk menggunakan kembali lapisan secara internal dan menerapkan pengoptimalan manajemen sumber daya.

Catatan

Dalam Windows 8 banyak pengoptimalan telah dilakukan untuk penggunaan lapisan dan kami sarankan Anda mencoba menggunakan API lapisan alih-alih FillGeometry jika memungkinkan.

 

Klip rata sumbu

Jika wilayah yang akan dipotong diselaraskan ke sumbu permukaan gambar, alih-alih arbitrer. Kasus ini cocok untuk menggunakan persegi klip alih-alih lapisan. Perolehan performa lebih untuk geometri alias daripada geometri yang diantisipasi. Untuk informasi selengkapnya tentang klip rata sumbu, lihat topik PushAxisAlignedClip .

Referensi Direct2D